160484Sobrien/* BFD back-end for ARM COFF files. 278828Sobrien Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 3218822Sdim 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 460484Sobrien Free Software Foundation, Inc. 560484Sobrien Written by Cygnus Support. 660484Sobrien 7130561Sobrien This file is part of BFD, the Binary File Descriptor library. 860484Sobrien 9130561Sobrien This program is free software; you can redistribute it and/or modify 10130561Sobrien it under the terms of the GNU General Public License as published by 11130561Sobrien the Free Software Foundation; either version 2 of the License, or 12130561Sobrien (at your option) any later version. 1360484Sobrien 14130561Sobrien This program is distributed in the hope that it will be useful, 15130561Sobrien but WITHOUT ANY WARRANTY; without even the implied warranty of 16130561Sobrien MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17130561Sobrien GNU General Public License for more details. 1860484Sobrien 19130561Sobrien You should have received a copy of the GNU General Public License 20130561Sobrien along with this program; if not, write to the Free Software 21218822Sdim Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 2260484Sobrien 23218822Sdim#include "sysdep.h" 2460484Sobrien#include "bfd.h" 2560484Sobrien#include "libbfd.h" 2660484Sobrien#include "coff/arm.h" 2760484Sobrien#include "coff/internal.h" 2860484Sobrien 2960484Sobrien#ifdef COFF_WITH_PE 3060484Sobrien#include "coff/pe.h" 3160484Sobrien#endif 3260484Sobrien 3360484Sobrien#include "libcoff.h" 3460484Sobrien 3560484Sobrien/* Macros for manipulation the bits in the flags field of the coff data 3660484Sobrien structure. */ 3789857Sobrien#define APCS_26_FLAG(abfd) \ 3889857Sobrien (coff_data (abfd)->flags & F_APCS_26) 3960484Sobrien 4089857Sobrien#define APCS_FLOAT_FLAG(abfd) \ 4189857Sobrien (coff_data (abfd)->flags & F_APCS_FLOAT) 4289857Sobrien 4389857Sobrien#define PIC_FLAG(abfd) \ 4489857Sobrien (coff_data (abfd)->flags & F_PIC) 4589857Sobrien 4689857Sobrien#define APCS_SET(abfd) \ 4789857Sobrien (coff_data (abfd)->flags & F_APCS_SET) 4889857Sobrien 4989857Sobrien#define SET_APCS_FLAGS(abfd, flgs) \ 5089857Sobrien do \ 5189857Sobrien { \ 5289857Sobrien coff_data (abfd)->flags &= ~(F_APCS_26 | F_APCS_FLOAT | F_PIC); \ 5389857Sobrien coff_data (abfd)->flags |= (flgs) | F_APCS_SET; \ 5489857Sobrien } \ 5589857Sobrien while (0) 5689857Sobrien 5789857Sobrien#define INTERWORK_FLAG(abfd) \ 5889857Sobrien (coff_data (abfd)->flags & F_INTERWORK) 5989857Sobrien 6089857Sobrien#define INTERWORK_SET(abfd) \ 6189857Sobrien (coff_data (abfd)->flags & F_INTERWORK_SET) 6289857Sobrien 6389857Sobrien#define SET_INTERWORK_FLAG(abfd, flg) \ 6489857Sobrien do \ 6589857Sobrien { \ 6689857Sobrien coff_data (abfd)->flags &= ~F_INTERWORK; \ 6789857Sobrien coff_data (abfd)->flags |= (flg) | F_INTERWORK_SET; \ 6889857Sobrien } \ 6989857Sobrien while (0) 7089857Sobrien 7160484Sobrien#ifndef NUM_ELEM 7260484Sobrien#define NUM_ELEM(a) ((sizeof (a)) / sizeof ((a)[0])) 7360484Sobrien#endif 7477298Sobrien 7560484Sobrientypedef enum {bunknown, b9, b12, b23} thumb_pcrel_branchtype; 76218822Sdim/* Some typedefs for holding instructions. */ 7760484Sobrientypedef unsigned long int insn32; 7860484Sobrientypedef unsigned short int insn16; 7960484Sobrien 8060484Sobrien/* The linker script knows the section names for placement. 8160484Sobrien The entry_names are used to do simple name mangling on the stubs. 8260484Sobrien Given a function name, and its type, the stub can be found. The 8389857Sobrien name can be changed. The only requirement is the %s be present. */ 8477298Sobrien 8560484Sobrien#define THUMB2ARM_GLUE_SECTION_NAME ".glue_7t" 8660484Sobrien#define THUMB2ARM_GLUE_ENTRY_NAME "__%s_from_thumb" 8760484Sobrien 8860484Sobrien#define ARM2THUMB_GLUE_SECTION_NAME ".glue_7" 8960484Sobrien#define ARM2THUMB_GLUE_ENTRY_NAME "__%s_from_arm" 9060484Sobrien 9177298Sobrien/* Used by the assembler. */ 9289857Sobrien 9360484Sobrienstatic bfd_reloc_status_type 94218822Sdimcoff_arm_reloc (bfd *abfd, 95218822Sdim arelent *reloc_entry, 96218822Sdim asymbol *symbol ATTRIBUTE_UNUSED, 97218822Sdim void * data, 98218822Sdim asection *input_section ATTRIBUTE_UNUSED, 99218822Sdim bfd *output_bfd, 100218822Sdim char **error_message ATTRIBUTE_UNUSED) 10160484Sobrien{ 10260484Sobrien symvalue diff; 103218822Sdim 104218822Sdim if (output_bfd == NULL) 10560484Sobrien return bfd_reloc_continue; 10660484Sobrien 10760484Sobrien diff = reloc_entry->addend; 10860484Sobrien 10989857Sobrien#define DOIT(x) \ 11089857Sobrien x = ((x & ~howto->dst_mask) \ 11189857Sobrien | (((x & howto->src_mask) + diff) & howto->dst_mask)) 11260484Sobrien 11360484Sobrien if (diff != 0) 11460484Sobrien { 11560484Sobrien reloc_howto_type *howto = reloc_entry->howto; 11660484Sobrien unsigned char *addr = (unsigned char *) data + reloc_entry->address; 11760484Sobrien 11860484Sobrien switch (howto->size) 11960484Sobrien { 12060484Sobrien case 0: 12160484Sobrien { 12260484Sobrien char x = bfd_get_8 (abfd, addr); 12360484Sobrien DOIT (x); 12460484Sobrien bfd_put_8 (abfd, x, addr); 12560484Sobrien } 12660484Sobrien break; 12760484Sobrien 12860484Sobrien case 1: 12960484Sobrien { 13060484Sobrien short x = bfd_get_16 (abfd, addr); 13160484Sobrien DOIT (x); 13289857Sobrien bfd_put_16 (abfd, (bfd_vma) x, addr); 13360484Sobrien } 13460484Sobrien break; 13560484Sobrien 13660484Sobrien case 2: 13760484Sobrien { 13860484Sobrien long x = bfd_get_32 (abfd, addr); 13960484Sobrien DOIT (x); 14089857Sobrien bfd_put_32 (abfd, (bfd_vma) x, addr); 14160484Sobrien } 14260484Sobrien break; 14360484Sobrien 14460484Sobrien default: 14560484Sobrien abort (); 14660484Sobrien } 14760484Sobrien } 14860484Sobrien 14960484Sobrien /* Now let bfd_perform_relocation finish everything up. */ 15060484Sobrien return bfd_reloc_continue; 15160484Sobrien} 15260484Sobrien 15360484Sobrien/* If USER_LABEL_PREFIX is defined as "_" (see coff_arm_is_local_label_name() 15460484Sobrien in this file), then TARGET_UNDERSCORE should be defined, otherwise it 15560484Sobrien should not. */ 15660484Sobrien#ifndef TARGET_UNDERSCORE 15760484Sobrien#define TARGET_UNDERSCORE '_' 15860484Sobrien#endif 15960484Sobrien 16060484Sobrien#ifndef PCRELOFFSET 161130561Sobrien#define PCRELOFFSET TRUE 16260484Sobrien#endif 16360484Sobrien 16460484Sobrien/* These most certainly belong somewhere else. Just had to get rid of 16560484Sobrien the manifest constants in the code. */ 166218822Sdim 167218822Sdim#ifdef ARM_WINCE 168218822Sdim 169218822Sdim#define ARM_26D 0 170218822Sdim#define ARM_32 1 171218822Sdim#define ARM_RVA32 2 172218822Sdim#define ARM_26 3 173218822Sdim#define ARM_THUMB12 4 174218822Sdim#define ARM_SECTION 14 175218822Sdim#define ARM_SECREL 15 176218822Sdim 177218822Sdim#else 178218822Sdim 17960484Sobrien#define ARM_8 0 18060484Sobrien#define ARM_16 1 18160484Sobrien#define ARM_32 2 18260484Sobrien#define ARM_26 3 18360484Sobrien#define ARM_DISP8 4 18460484Sobrien#define ARM_DISP16 5 18560484Sobrien#define ARM_DISP32 6 18660484Sobrien#define ARM_26D 7 187218822Sdim/* 8 is unused. */ 18860484Sobrien#define ARM_NEG16 9 18960484Sobrien#define ARM_NEG32 10 19060484Sobrien#define ARM_RVA32 11 19160484Sobrien#define ARM_THUMB9 12 19260484Sobrien#define ARM_THUMB12 13 19360484Sobrien#define ARM_THUMB23 14 19460484Sobrien 195218822Sdim#endif 19660484Sobrien 197218822Sdimstatic bfd_reloc_status_type aoutarm_fix_pcrel_26_done 198218822Sdim (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); 199218822Sdimstatic bfd_reloc_status_type aoutarm_fix_pcrel_26 200218822Sdim (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); 201218822Sdimstatic bfd_reloc_status_type coff_thumb_pcrel_12 202218822Sdim (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); 203218822Sdim#ifndef ARM_WINCE 204218822Sdimstatic bfd_reloc_status_type coff_thumb_pcrel_9 205218822Sdim (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); 206218822Sdimstatic bfd_reloc_status_type coff_thumb_pcrel_23 207218822Sdim (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); 20860484Sobrien#endif 20960484Sobrien 21077298Sobrienstatic reloc_howto_type aoutarm_std_reloc_howto[] = 21189857Sobrien { 21260484Sobrien#ifdef ARM_WINCE 213130561Sobrien HOWTO (ARM_26D, 214130561Sobrien 2, 215130561Sobrien 2, 216130561Sobrien 24, 217130561Sobrien TRUE, 218130561Sobrien 0, 219130561Sobrien complain_overflow_dont, 220130561Sobrien aoutarm_fix_pcrel_26_done, 221130561Sobrien "ARM_26D", 222218822Sdim TRUE, /* partial_inplace. */ 223130561Sobrien 0x00ffffff, 224130561Sobrien 0x0, 225130561Sobrien PCRELOFFSET), 22689857Sobrien HOWTO (ARM_32, 22789857Sobrien 0, 22889857Sobrien 2, 22989857Sobrien 32, 230130561Sobrien FALSE, 23189857Sobrien 0, 23289857Sobrien complain_overflow_bitfield, 23389857Sobrien coff_arm_reloc, 23489857Sobrien "ARM_32", 235218822Sdim TRUE, /* partial_inplace. */ 23689857Sobrien 0xffffffff, 23789857Sobrien 0xffffffff, 23889857Sobrien PCRELOFFSET), 23989857Sobrien HOWTO (ARM_RVA32, 24089857Sobrien 0, 24189857Sobrien 2, 24289857Sobrien 32, 243130561Sobrien FALSE, 24489857Sobrien 0, 24589857Sobrien complain_overflow_bitfield, 24689857Sobrien coff_arm_reloc, 24789857Sobrien "ARM_RVA32", 248218822Sdim TRUE, /* partial_inplace. */ 24989857Sobrien 0xffffffff, 25089857Sobrien 0xffffffff, 25189857Sobrien PCRELOFFSET), 25289857Sobrien HOWTO (ARM_26, 25389857Sobrien 2, 25489857Sobrien 2, 25589857Sobrien 24, 256130561Sobrien TRUE, 25789857Sobrien 0, 25889857Sobrien complain_overflow_signed, 25989857Sobrien aoutarm_fix_pcrel_26 , 26089857Sobrien "ARM_26", 261130561Sobrien FALSE, 26289857Sobrien 0x00ffffff, 26389857Sobrien 0x00ffffff, 26489857Sobrien PCRELOFFSET), 26589857Sobrien HOWTO (ARM_THUMB12, 26689857Sobrien 1, 26789857Sobrien 1, 26889857Sobrien 11, 269130561Sobrien TRUE, 27089857Sobrien 0, 27189857Sobrien complain_overflow_signed, 27289857Sobrien coff_thumb_pcrel_12 , 27389857Sobrien "ARM_THUMB12", 274130561Sobrien FALSE, 27589857Sobrien 0x000007ff, 27689857Sobrien 0x000007ff, 27789857Sobrien PCRELOFFSET), 27889857Sobrien EMPTY_HOWTO (-1), 27989857Sobrien EMPTY_HOWTO (-1), 28089857Sobrien EMPTY_HOWTO (-1), 28189857Sobrien EMPTY_HOWTO (-1), 28289857Sobrien EMPTY_HOWTO (-1), 28389857Sobrien EMPTY_HOWTO (-1), 28489857Sobrien EMPTY_HOWTO (-1), 28589857Sobrien EMPTY_HOWTO (-1), 286130561Sobrien EMPTY_HOWTO (-1), 28789857Sobrien HOWTO (ARM_SECTION, 28889857Sobrien 0, 28989857Sobrien 1, 29089857Sobrien 16, 291130561Sobrien FALSE, 29289857Sobrien 0, 29389857Sobrien complain_overflow_bitfield, 29489857Sobrien coff_arm_reloc, 295130561Sobrien "ARM_SECTION", 296218822Sdim TRUE, /* partial_inplace. */ 29789857Sobrien 0x0000ffff, 29889857Sobrien 0x0000ffff, 29989857Sobrien PCRELOFFSET), 30089857Sobrien HOWTO (ARM_SECREL, 30189857Sobrien 0, 30289857Sobrien 2, 30389857Sobrien 32, 304130561Sobrien FALSE, 30589857Sobrien 0, 30689857Sobrien complain_overflow_bitfield, 30789857Sobrien coff_arm_reloc, 308130561Sobrien "ARM_SECREL", 309218822Sdim TRUE, /* partial_inplace. */ 31089857Sobrien 0xffffffff, 31189857Sobrien 0xffffffff, 31289857Sobrien PCRELOFFSET), 31360484Sobrien#else /* not ARM_WINCE */ 314218822Sdim HOWTO (ARM_8, 315218822Sdim 0, 316218822Sdim 0, 317218822Sdim 8, 318218822Sdim FALSE, 319218822Sdim 0, 320218822Sdim complain_overflow_bitfield, 321218822Sdim coff_arm_reloc, 322218822Sdim "ARM_8", 323218822Sdim TRUE, 324218822Sdim 0x000000ff, 325218822Sdim 0x000000ff, 326218822Sdim PCRELOFFSET), 32789857Sobrien HOWTO (ARM_16, 32889857Sobrien 0, 32989857Sobrien 1, 33089857Sobrien 16, 331130561Sobrien FALSE, 33289857Sobrien 0, 33389857Sobrien complain_overflow_bitfield, 33489857Sobrien coff_arm_reloc, 33589857Sobrien "ARM_16", 336130561Sobrien TRUE, 33789857Sobrien 0x0000ffff, 33889857Sobrien 0x0000ffff, 33989857Sobrien PCRELOFFSET), 34089857Sobrien HOWTO (ARM_32, 34189857Sobrien 0, 34289857Sobrien 2, 34389857Sobrien 32, 344130561Sobrien FALSE, 34589857Sobrien 0, 34689857Sobrien complain_overflow_bitfield, 34789857Sobrien coff_arm_reloc, 34889857Sobrien "ARM_32", 349130561Sobrien TRUE, 35089857Sobrien 0xffffffff, 35189857Sobrien 0xffffffff, 35289857Sobrien PCRELOFFSET), 35389857Sobrien HOWTO (ARM_26, 35489857Sobrien 2, 35589857Sobrien 2, 35689857Sobrien 24, 357130561Sobrien TRUE, 35889857Sobrien 0, 35989857Sobrien complain_overflow_signed, 36089857Sobrien aoutarm_fix_pcrel_26 , 36189857Sobrien "ARM_26", 362130561Sobrien FALSE, 36389857Sobrien 0x00ffffff, 36489857Sobrien 0x00ffffff, 36589857Sobrien PCRELOFFSET), 36689857Sobrien HOWTO (ARM_DISP8, 36789857Sobrien 0, 36889857Sobrien 0, 36989857Sobrien 8, 370130561Sobrien TRUE, 37189857Sobrien 0, 37289857Sobrien complain_overflow_signed, 37389857Sobrien coff_arm_reloc, 37489857Sobrien "ARM_DISP8", 375130561Sobrien TRUE, 37689857Sobrien 0x000000ff, 37789857Sobrien 0x000000ff, 378130561Sobrien TRUE), 37989857Sobrien HOWTO (ARM_DISP16, 38089857Sobrien 0, 38189857Sobrien 1, 38289857Sobrien 16, 383130561Sobrien TRUE, 38489857Sobrien 0, 38589857Sobrien complain_overflow_signed, 38689857Sobrien coff_arm_reloc, 38789857Sobrien "ARM_DISP16", 388130561Sobrien TRUE, 38989857Sobrien 0x0000ffff, 39089857Sobrien 0x0000ffff, 391130561Sobrien TRUE), 39289857Sobrien HOWTO (ARM_DISP32, 39389857Sobrien 0, 39489857Sobrien 2, 39589857Sobrien 32, 396130561Sobrien TRUE, 39789857Sobrien 0, 39889857Sobrien complain_overflow_signed, 39989857Sobrien coff_arm_reloc, 40089857Sobrien "ARM_DISP32", 401130561Sobrien TRUE, 40289857Sobrien 0xffffffff, 40389857Sobrien 0xffffffff, 404130561Sobrien TRUE), 40589857Sobrien HOWTO (ARM_26D, 40689857Sobrien 2, 40789857Sobrien 2, 40889857Sobrien 24, 409130561Sobrien FALSE, 41089857Sobrien 0, 41189857Sobrien complain_overflow_dont, 41289857Sobrien aoutarm_fix_pcrel_26_done, 41389857Sobrien "ARM_26D", 414130561Sobrien TRUE, 41589857Sobrien 0x00ffffff, 41689857Sobrien 0x0, 417130561Sobrien FALSE), 41889857Sobrien /* 8 is unused */ 41989857Sobrien EMPTY_HOWTO (-1), 42089857Sobrien HOWTO (ARM_NEG16, 42189857Sobrien 0, 42289857Sobrien -1, 42389857Sobrien 16, 424130561Sobrien FALSE, 42589857Sobrien 0, 42689857Sobrien complain_overflow_bitfield, 42789857Sobrien coff_arm_reloc, 42889857Sobrien "ARM_NEG16", 429130561Sobrien TRUE, 43089857Sobrien 0x0000ffff, 43189857Sobrien 0x0000ffff, 432130561Sobrien FALSE), 43389857Sobrien HOWTO (ARM_NEG32, 43489857Sobrien 0, 43589857Sobrien -2, 43689857Sobrien 32, 437130561Sobrien FALSE, 43889857Sobrien 0, 43989857Sobrien complain_overflow_bitfield, 44089857Sobrien coff_arm_reloc, 44189857Sobrien "ARM_NEG32", 442130561Sobrien TRUE, 44389857Sobrien 0xffffffff, 44489857Sobrien 0xffffffff, 445130561Sobrien FALSE), 44689857Sobrien HOWTO (ARM_RVA32, 44789857Sobrien 0, 44889857Sobrien 2, 44989857Sobrien 32, 450130561Sobrien FALSE, 45189857Sobrien 0, 45289857Sobrien complain_overflow_bitfield, 45389857Sobrien coff_arm_reloc, 45489857Sobrien "ARM_RVA32", 455130561Sobrien TRUE, 45689857Sobrien 0xffffffff, 45789857Sobrien 0xffffffff, 45889857Sobrien PCRELOFFSET), 45989857Sobrien HOWTO (ARM_THUMB9, 46089857Sobrien 1, 46189857Sobrien 1, 46289857Sobrien 8, 463130561Sobrien TRUE, 46489857Sobrien 0, 46589857Sobrien complain_overflow_signed, 46689857Sobrien coff_thumb_pcrel_9 , 46789857Sobrien "ARM_THUMB9", 468130561Sobrien FALSE, 46989857Sobrien 0x000000ff, 47089857Sobrien 0x000000ff, 47189857Sobrien PCRELOFFSET), 47289857Sobrien HOWTO (ARM_THUMB12, 47389857Sobrien 1, 47489857Sobrien 1, 47589857Sobrien 11, 476130561Sobrien TRUE, 47789857Sobrien 0, 47889857Sobrien complain_overflow_signed, 47989857Sobrien coff_thumb_pcrel_12 , 48089857Sobrien "ARM_THUMB12", 481130561Sobrien FALSE, 48289857Sobrien 0x000007ff, 48389857Sobrien 0x000007ff, 48489857Sobrien PCRELOFFSET), 48589857Sobrien HOWTO (ARM_THUMB23, 48689857Sobrien 1, 48789857Sobrien 2, 48889857Sobrien 22, 489130561Sobrien TRUE, 49089857Sobrien 0, 49189857Sobrien complain_overflow_signed, 49289857Sobrien coff_thumb_pcrel_23 , 49389857Sobrien "ARM_THUMB23", 494130561Sobrien FALSE, 49589857Sobrien 0x07ff07ff, 49689857Sobrien 0x07ff07ff, 49789857Sobrien PCRELOFFSET) 49860484Sobrien#endif /* not ARM_WINCE */ 49989857Sobrien }; 50060484Sobrien 50160484Sobrien#define NUM_RELOCS NUM_ELEM (aoutarm_std_reloc_howto) 50260484Sobrien 50360484Sobrien#ifdef COFF_WITH_PE 504130561Sobrien/* Return TRUE if this relocation should 50577298Sobrien appear in the output .reloc section. */ 50660484Sobrien 507130561Sobrienstatic bfd_boolean 508218822Sdimin_reloc_p (bfd * abfd ATTRIBUTE_UNUSED, 509218822Sdim reloc_howto_type * howto) 51060484Sobrien{ 51160484Sobrien return !howto->pc_relative && howto->type != ARM_RVA32; 51277298Sobrien} 51360484Sobrien#endif 51460484Sobrien 51560484Sobrien#define RTYPE2HOWTO(cache_ptr, dst) \ 51660484Sobrien (cache_ptr)->howto = \ 51760484Sobrien (dst)->r_type < NUM_RELOCS \ 51860484Sobrien ? aoutarm_std_reloc_howto + (dst)->r_type \ 51960484Sobrien : NULL 52060484Sobrien 52160484Sobrien#define coff_rtype_to_howto coff_arm_rtype_to_howto 52260484Sobrien 52360484Sobrienstatic reloc_howto_type * 524218822Sdimcoff_arm_rtype_to_howto (bfd *abfd ATTRIBUTE_UNUSED, 525218822Sdim asection *sec, 526218822Sdim struct internal_reloc *rel, 527218822Sdim struct coff_link_hash_entry *h ATTRIBUTE_UNUSED, 528218822Sdim struct internal_syment *sym ATTRIBUTE_UNUSED, 529218822Sdim bfd_vma *addendp) 53060484Sobrien{ 53160484Sobrien reloc_howto_type * howto; 53260484Sobrien 53360484Sobrien if (rel->r_type >= NUM_RELOCS) 53460484Sobrien return NULL; 53577298Sobrien 53660484Sobrien howto = aoutarm_std_reloc_howto + rel->r_type; 53760484Sobrien 53860484Sobrien if (rel->r_type == ARM_RVA32) 53960484Sobrien *addendp -= pe_data (sec->output_section->owner)->pe_opthdr.ImageBase; 54060484Sobrien 541218822Sdim#if defined COFF_WITH_PE && defined ARM_WINCE 542218822Sdim if (rel->r_type == ARM_SECREL) 543218822Sdim { 544218822Sdim bfd_vma osect_vma; 545218822Sdim 546218822Sdim if (h && (h->type == bfd_link_hash_defined 547218822Sdim || h->type == bfd_link_hash_defweak)) 548218822Sdim osect_vma = h->root.u.def.section->output_section->vma; 549218822Sdim else 550218822Sdim { 551218822Sdim asection *sec; 552218822Sdim int i; 553218822Sdim 554218822Sdim /* Sigh, the only way to get the section to offset against 555218822Sdim is to find it the hard way. */ 556218822Sdim 557218822Sdim for (sec = abfd->sections, i = 1; i < sym->n_scnum; i++) 558218822Sdim sec = sec->next; 559218822Sdim 560218822Sdim osect_vma = sec->output_section->vma; 561218822Sdim } 562218822Sdim 563218822Sdim *addendp -= osect_vma; 564218822Sdim } 565218822Sdim#endif 566218822Sdim 56760484Sobrien return howto; 56860484Sobrien} 56989857Sobrien 57077298Sobrien/* Used by the assembler. */ 57160484Sobrien 57260484Sobrienstatic bfd_reloc_status_type 573218822Sdimaoutarm_fix_pcrel_26_done (bfd *abfd ATTRIBUTE_UNUSED, 574218822Sdim arelent *reloc_entry ATTRIBUTE_UNUSED, 575218822Sdim asymbol *symbol ATTRIBUTE_UNUSED, 576218822Sdim void * data ATTRIBUTE_UNUSED, 577218822Sdim asection *input_section ATTRIBUTE_UNUSED, 578218822Sdim bfd *output_bfd ATTRIBUTE_UNUSED, 579218822Sdim char **error_message ATTRIBUTE_UNUSED) 58060484Sobrien{ 58160484Sobrien /* This is dead simple at present. */ 58260484Sobrien return bfd_reloc_ok; 58360484Sobrien} 58460484Sobrien 58577298Sobrien/* Used by the assembler. */ 58660484Sobrien 58760484Sobrienstatic bfd_reloc_status_type 588218822Sdimaoutarm_fix_pcrel_26 (bfd *abfd, 589218822Sdim arelent *reloc_entry, 590218822Sdim asymbol *symbol, 591218822Sdim void * data, 592218822Sdim asection *input_section, 593218822Sdim bfd *output_bfd, 594218822Sdim char **error_message ATTRIBUTE_UNUSED) 59560484Sobrien{ 59660484Sobrien bfd_vma relocation; 59760484Sobrien bfd_size_type addr = reloc_entry->address; 59860484Sobrien long target = bfd_get_32 (abfd, (bfd_byte *) data + addr); 59960484Sobrien bfd_reloc_status_type flag = bfd_reloc_ok; 60077298Sobrien 60189857Sobrien /* If this is an undefined symbol, return error. */ 60260484Sobrien if (symbol->section == &bfd_und_section 60360484Sobrien && (symbol->flags & BSF_WEAK) == 0) 60460484Sobrien return output_bfd ? bfd_reloc_continue : bfd_reloc_undefined; 60560484Sobrien 60660484Sobrien /* If the sections are different, and we are doing a partial relocation, 60760484Sobrien just ignore it for now. */ 60860484Sobrien if (symbol->section->name != input_section->name 60960484Sobrien && output_bfd != (bfd *)NULL) 61060484Sobrien return bfd_reloc_continue; 61160484Sobrien 61260484Sobrien relocation = (target & 0x00ffffff) << 2; 61389857Sobrien relocation = (relocation ^ 0x02000000) - 0x02000000; /* Sign extend. */ 61460484Sobrien relocation += symbol->value; 61560484Sobrien relocation += symbol->section->output_section->vma; 61660484Sobrien relocation += symbol->section->output_offset; 61760484Sobrien relocation += reloc_entry->addend; 61860484Sobrien relocation -= input_section->output_section->vma; 61960484Sobrien relocation -= input_section->output_offset; 62060484Sobrien relocation -= addr; 62177298Sobrien 62260484Sobrien if (relocation & 3) 62360484Sobrien return bfd_reloc_overflow; 62460484Sobrien 62589857Sobrien /* Check for overflow. */ 62660484Sobrien if (relocation & 0x02000000) 62760484Sobrien { 62860484Sobrien if ((relocation & ~ (bfd_vma) 0x03ffffff) != ~ (bfd_vma) 0x03ffffff) 62960484Sobrien flag = bfd_reloc_overflow; 63060484Sobrien } 63189857Sobrien else if (relocation & ~(bfd_vma) 0x03ffffff) 63260484Sobrien flag = bfd_reloc_overflow; 63360484Sobrien 63460484Sobrien target &= ~0x00ffffff; 63560484Sobrien target |= (relocation >> 2) & 0x00ffffff; 63689857Sobrien bfd_put_32 (abfd, (bfd_vma) target, (bfd_byte *) data + addr); 63760484Sobrien 63860484Sobrien /* Now the ARM magic... Change the reloc type so that it is marked as done. 63960484Sobrien Strictly this is only necessary if we are doing a partial relocation. */ 64060484Sobrien reloc_entry->howto = &aoutarm_std_reloc_howto[ARM_26D]; 64160484Sobrien 64260484Sobrien return flag; 64360484Sobrien} 64460484Sobrien 64560484Sobrienstatic bfd_reloc_status_type 646218822Sdimcoff_thumb_pcrel_common (bfd *abfd, 647218822Sdim arelent *reloc_entry, 648218822Sdim asymbol *symbol, 649218822Sdim void * data, 650218822Sdim asection *input_section, 651218822Sdim bfd *output_bfd, 652218822Sdim char **error_message ATTRIBUTE_UNUSED, 653218822Sdim thumb_pcrel_branchtype btype) 65460484Sobrien{ 65560484Sobrien bfd_vma relocation = 0; 65660484Sobrien bfd_size_type addr = reloc_entry->address; 65760484Sobrien long target = bfd_get_32 (abfd, (bfd_byte *) data + addr); 65860484Sobrien bfd_reloc_status_type flag = bfd_reloc_ok; 65960484Sobrien bfd_vma dstmsk; 66060484Sobrien bfd_vma offmsk; 66160484Sobrien bfd_vma signbit; 66260484Sobrien 66360484Sobrien /* NOTE: This routine is currently used by GAS, but not by the link 66460484Sobrien phase. */ 66560484Sobrien switch (btype) 66660484Sobrien { 66760484Sobrien case b9: 66860484Sobrien dstmsk = 0x000000ff; 66960484Sobrien offmsk = 0x000001fe; 67060484Sobrien signbit = 0x00000100; 67160484Sobrien break; 67260484Sobrien 67360484Sobrien case b12: 67460484Sobrien dstmsk = 0x000007ff; 67560484Sobrien offmsk = 0x00000ffe; 67660484Sobrien signbit = 0x00000800; 67760484Sobrien break; 67860484Sobrien 67960484Sobrien case b23: 68060484Sobrien dstmsk = 0x07ff07ff; 68160484Sobrien offmsk = 0x007fffff; 68260484Sobrien signbit = 0x00400000; 68360484Sobrien break; 68460484Sobrien 68560484Sobrien default: 68660484Sobrien abort (); 68760484Sobrien } 68877298Sobrien 68989857Sobrien /* If this is an undefined symbol, return error. */ 69060484Sobrien if (symbol->section == &bfd_und_section 69160484Sobrien && (symbol->flags & BSF_WEAK) == 0) 69260484Sobrien return output_bfd ? bfd_reloc_continue : bfd_reloc_undefined; 69360484Sobrien 69460484Sobrien /* If the sections are different, and we are doing a partial relocation, 69560484Sobrien just ignore it for now. */ 69660484Sobrien if (symbol->section->name != input_section->name 69760484Sobrien && output_bfd != (bfd *)NULL) 69860484Sobrien return bfd_reloc_continue; 69960484Sobrien 70060484Sobrien switch (btype) 70160484Sobrien { 70260484Sobrien case b9: 70360484Sobrien case b12: 70460484Sobrien relocation = ((target & dstmsk) << 1); 70560484Sobrien break; 70660484Sobrien 70760484Sobrien case b23: 70860484Sobrien if (bfd_big_endian (abfd)) 70960484Sobrien relocation = ((target & 0x7ff) << 1) | ((target & 0x07ff0000) >> 4); 71060484Sobrien else 71160484Sobrien relocation = ((target & 0x7ff) << 12) | ((target & 0x07ff0000) >> 15); 71260484Sobrien break; 71360484Sobrien 71460484Sobrien default: 71560484Sobrien abort (); 71660484Sobrien } 71760484Sobrien 71889857Sobrien relocation = (relocation ^ signbit) - signbit; /* Sign extend. */ 71960484Sobrien relocation += symbol->value; 72060484Sobrien relocation += symbol->section->output_section->vma; 72160484Sobrien relocation += symbol->section->output_offset; 72260484Sobrien relocation += reloc_entry->addend; 72360484Sobrien relocation -= input_section->output_section->vma; 72460484Sobrien relocation -= input_section->output_offset; 72560484Sobrien relocation -= addr; 72660484Sobrien 72760484Sobrien if (relocation & 1) 72860484Sobrien return bfd_reloc_overflow; 72960484Sobrien 73089857Sobrien /* Check for overflow. */ 73160484Sobrien if (relocation & signbit) 73260484Sobrien { 73360484Sobrien if ((relocation & ~offmsk) != ~offmsk) 73460484Sobrien flag = bfd_reloc_overflow; 73560484Sobrien } 73660484Sobrien else if (relocation & ~offmsk) 73760484Sobrien flag = bfd_reloc_overflow; 73860484Sobrien 73960484Sobrien target &= ~dstmsk; 74060484Sobrien switch (btype) 74160484Sobrien { 74260484Sobrien case b9: 74360484Sobrien case b12: 74460484Sobrien target |= (relocation >> 1); 74560484Sobrien break; 74660484Sobrien 74760484Sobrien case b23: 74860484Sobrien if (bfd_big_endian (abfd)) 74989857Sobrien target |= (((relocation & 0xfff) >> 1) 75089857Sobrien | ((relocation << 4) & 0x07ff0000)); 75160484Sobrien else 75289857Sobrien target |= (((relocation & 0xffe) << 15) 75389857Sobrien | ((relocation >> 12) & 0x7ff)); 75460484Sobrien break; 75560484Sobrien 75660484Sobrien default: 75760484Sobrien abort (); 75860484Sobrien } 75960484Sobrien 76089857Sobrien bfd_put_32 (abfd, (bfd_vma) target, (bfd_byte *) data + addr); 76160484Sobrien 76260484Sobrien /* Now the ARM magic... Change the reloc type so that it is marked as done. 76360484Sobrien Strictly this is only necessary if we are doing a partial relocation. */ 76460484Sobrien reloc_entry->howto = & aoutarm_std_reloc_howto [ARM_26D]; 76577298Sobrien 76689857Sobrien /* TODO: We should possibly have DONE entries for the THUMB PCREL relocations. */ 76760484Sobrien return flag; 76860484Sobrien} 76960484Sobrien 77099461Sobrien#ifndef ARM_WINCE 77160484Sobrienstatic bfd_reloc_status_type 772218822Sdimcoff_thumb_pcrel_23 (bfd *abfd, 773218822Sdim arelent *reloc_entry, 774218822Sdim asymbol *symbol, 775218822Sdim void * data, 776218822Sdim asection *input_section, 777218822Sdim bfd *output_bfd, 778218822Sdim char **error_message) 77960484Sobrien{ 78060484Sobrien return coff_thumb_pcrel_common (abfd, reloc_entry, symbol, data, 78189857Sobrien input_section, output_bfd, error_message, 78289857Sobrien b23); 78360484Sobrien} 78460484Sobrien 78560484Sobrienstatic bfd_reloc_status_type 786218822Sdimcoff_thumb_pcrel_9 (bfd *abfd, 787218822Sdim arelent *reloc_entry, 788218822Sdim asymbol *symbol, 789218822Sdim void * data, 790218822Sdim asection *input_section, 791218822Sdim bfd *output_bfd, 792218822Sdim char **error_message) 79360484Sobrien{ 79460484Sobrien return coff_thumb_pcrel_common (abfd, reloc_entry, symbol, data, 79589857Sobrien input_section, output_bfd, error_message, 79699461Sobrien b9); 79760484Sobrien} 79899461Sobrien#endif /* not ARM_WINCE */ 79960484Sobrien 80060484Sobrienstatic bfd_reloc_status_type 801218822Sdimcoff_thumb_pcrel_12 (bfd *abfd, 802218822Sdim arelent *reloc_entry, 803218822Sdim asymbol *symbol, 804218822Sdim void * data, 805218822Sdim asection *input_section, 806218822Sdim bfd *output_bfd, 807218822Sdim char **error_message) 80860484Sobrien{ 80960484Sobrien return coff_thumb_pcrel_common (abfd, reloc_entry, symbol, data, 81089857Sobrien input_section, output_bfd, error_message, 81199461Sobrien b12); 81260484Sobrien} 81360484Sobrien 81489857Sobrienstatic const struct reloc_howto_struct * 815218822Sdimcoff_arm_reloc_type_lookup (bfd * abfd, bfd_reloc_code_real_type code) 81660484Sobrien{ 81760484Sobrien#define ASTD(i,j) case i: return aoutarm_std_reloc_howto + j 81877298Sobrien 81960484Sobrien if (code == BFD_RELOC_CTOR) 82060484Sobrien switch (bfd_get_arch_info (abfd)->bits_per_address) 82160484Sobrien { 82260484Sobrien case 32: 82360484Sobrien code = BFD_RELOC_32; 82460484Sobrien break; 82589857Sobrien default: 826218822Sdim return NULL; 82760484Sobrien } 82860484Sobrien 82960484Sobrien switch (code) 83060484Sobrien { 83160484Sobrien#ifdef ARM_WINCE 83260484Sobrien ASTD (BFD_RELOC_32, ARM_32); 83360484Sobrien ASTD (BFD_RELOC_RVA, ARM_RVA32); 83460484Sobrien ASTD (BFD_RELOC_ARM_PCREL_BRANCH, ARM_26); 83560484Sobrien ASTD (BFD_RELOC_THUMB_PCREL_BRANCH12, ARM_THUMB12); 836218822Sdim ASTD (BFD_RELOC_32_SECREL, ARM_SECREL); 83760484Sobrien#else 83860484Sobrien ASTD (BFD_RELOC_8, ARM_8); 83960484Sobrien ASTD (BFD_RELOC_16, ARM_16); 84060484Sobrien ASTD (BFD_RELOC_32, ARM_32); 84160484Sobrien ASTD (BFD_RELOC_ARM_PCREL_BRANCH, ARM_26); 84277298Sobrien ASTD (BFD_RELOC_ARM_PCREL_BLX, ARM_26); 84360484Sobrien ASTD (BFD_RELOC_8_PCREL, ARM_DISP8); 84460484Sobrien ASTD (BFD_RELOC_16_PCREL, ARM_DISP16); 84560484Sobrien ASTD (BFD_RELOC_32_PCREL, ARM_DISP32); 84660484Sobrien ASTD (BFD_RELOC_RVA, ARM_RVA32); 84760484Sobrien ASTD (BFD_RELOC_THUMB_PCREL_BRANCH9, ARM_THUMB9); 84860484Sobrien ASTD (BFD_RELOC_THUMB_PCREL_BRANCH12, ARM_THUMB12); 84960484Sobrien ASTD (BFD_RELOC_THUMB_PCREL_BRANCH23, ARM_THUMB23); 85078828Sobrien ASTD (BFD_RELOC_THUMB_PCREL_BLX, ARM_THUMB23); 85177298Sobrien#endif 852218822Sdim default: return NULL; 85360484Sobrien } 85460484Sobrien} 85560484Sobrien 856218822Sdimstatic reloc_howto_type * 857218822Sdimcoff_arm_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, 858218822Sdim const char *r_name) 859218822Sdim{ 860218822Sdim unsigned int i; 86160484Sobrien 862218822Sdim for (i = 0; 863218822Sdim i < (sizeof (aoutarm_std_reloc_howto) 864218822Sdim / sizeof (aoutarm_std_reloc_howto[0])); 865218822Sdim i++) 866218822Sdim if (aoutarm_std_reloc_howto[i].name != NULL 867218822Sdim && strcasecmp (aoutarm_std_reloc_howto[i].name, r_name) == 0) 868218822Sdim return &aoutarm_std_reloc_howto[i]; 869218822Sdim 870218822Sdim return NULL; 871218822Sdim} 872218822Sdim 873218822Sdim#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER 2 874218822Sdim#define COFF_PAGE_SIZE 0x1000 875218822Sdim 876218822Sdim/* Turn a howto into a reloc nunmber. */ 87760484Sobrien#define SELECT_RELOC(x,howto) { x.r_type = howto->type; } 878218822Sdim#define BADMAG(x) ARMBADMAG(x) 879218822Sdim#define ARM 1 /* Customize coffcode.h. */ 88060484Sobrien 88199461Sobrien#ifndef ARM_WINCE 88294536Sobrien/* Make sure that the 'r_offset' field is copied properly 88394536Sobrien so that identical binaries will compare the same. */ 88494536Sobrien#define SWAP_IN_RELOC_OFFSET H_GET_32 88594536Sobrien#define SWAP_OUT_RELOC_OFFSET H_PUT_32 88699461Sobrien#endif 88794536Sobrien 88860484Sobrien/* Extend the coff_link_hash_table structure with a few ARM specific fields. 88960484Sobrien This allows us to store global data here without actually creating any 89060484Sobrien global variables, which is a no-no in the BFD world. */ 89160484Sobrienstruct coff_arm_link_hash_table 89289857Sobrien { 89389857Sobrien /* The original coff_link_hash_table structure. MUST be first field. */ 89489857Sobrien struct coff_link_hash_table root; 89577298Sobrien 896130561Sobrien /* The size in bytes of the section containing the Thumb-to-ARM glue. */ 89789857Sobrien bfd_size_type thumb_glue_size; 89877298Sobrien 899130561Sobrien /* The size in bytes of the section containing the ARM-to-Thumb glue. */ 90089857Sobrien bfd_size_type arm_glue_size; 90160484Sobrien 902130561Sobrien /* An arbitrary input BFD chosen to hold the glue sections. */ 90389857Sobrien bfd * bfd_of_glue_owner; 90460484Sobrien 90589857Sobrien /* Support interworking with old, non-interworking aware ARM code. */ 90689857Sobrien int support_old_code; 90760484Sobrien}; 90860484Sobrien 90960484Sobrien/* Get the ARM coff linker hash table from a link_info structure. */ 91060484Sobrien#define coff_arm_hash_table(info) \ 91160484Sobrien ((struct coff_arm_link_hash_table *) ((info)->hash)) 91260484Sobrien 91360484Sobrien/* Create an ARM coff linker hash table. */ 91460484Sobrien 91560484Sobrienstatic struct bfd_link_hash_table * 916218822Sdimcoff_arm_link_hash_table_create (bfd * abfd) 91760484Sobrien{ 91860484Sobrien struct coff_arm_link_hash_table * ret; 91989857Sobrien bfd_size_type amt = sizeof (struct coff_arm_link_hash_table); 92060484Sobrien 921218822Sdim ret = bfd_malloc (amt); 922218822Sdim if (ret == NULL) 92360484Sobrien return NULL; 92460484Sobrien 925218822Sdim if (!_bfd_coff_link_hash_table_init (&ret->root, 926218822Sdim abfd, 927218822Sdim _bfd_coff_link_hash_newfunc, 928218822Sdim sizeof (struct coff_link_hash_entry))) 92960484Sobrien { 930104834Sobrien free (ret); 931218822Sdim return NULL; 93260484Sobrien } 93360484Sobrien 93460484Sobrien ret->thumb_glue_size = 0; 93560484Sobrien ret->arm_glue_size = 0; 93660484Sobrien ret->bfd_of_glue_owner = NULL; 93760484Sobrien 93860484Sobrien return & ret->root.root; 93960484Sobrien} 94060484Sobrien 94160484Sobrienstatic void 942218822Sdimarm_emit_base_file_entry (struct bfd_link_info *info, 943218822Sdim bfd *output_bfd, 944218822Sdim asection *input_section, 945218822Sdim bfd_vma reloc_offset) 94660484Sobrien{ 94760484Sobrien bfd_vma addr = reloc_offset 94860484Sobrien - input_section->vma 94960484Sobrien + input_section->output_offset 95060484Sobrien + input_section->output_section->vma; 95160484Sobrien 95289857Sobrien if (coff_data (output_bfd)->pe) 95389857Sobrien addr -= pe_data (output_bfd)->pe_opthdr.ImageBase; 95489857Sobrien fwrite (& addr, 1, sizeof (addr), (FILE *) info->base_file); 95560484Sobrien 95660484Sobrien} 95760484Sobrien 95899461Sobrien#ifndef ARM_WINCE 95960484Sobrien/* The thumb form of a long branch is a bit finicky, because the offset 96060484Sobrien encoding is split over two fields, each in it's own instruction. They 96177298Sobrien can occur in any order. So given a thumb form of long branch, and an 96260484Sobrien offset, insert the offset into the thumb branch and return finished 96377298Sobrien instruction. 96460484Sobrien 96577298Sobrien It takes two thumb instructions to encode the target address. Each has 966130561Sobrien 11 bits to invest. The upper 11 bits are stored in one (identified by 96777298Sobrien H-0.. see below), the lower 11 bits are stored in the other (identified 96877298Sobrien by H-1). 96960484Sobrien 97077298Sobrien Combine together and shifted left by 1 (it's a half word address) and 97160484Sobrien there you have it. 97260484Sobrien 97360484Sobrien Op: 1111 = F, 97460484Sobrien H-0, upper address-0 = 000 97560484Sobrien Op: 1111 = F, 97660484Sobrien H-1, lower address-0 = 800 97760484Sobrien 97877298Sobrien They can be ordered either way, but the arm tools I've seen always put 97960484Sobrien the lower one first. It probably doesn't matter. krk@cygnus.com 98060484Sobrien 98160484Sobrien XXX: Actually the order does matter. The second instruction (H-1) 98260484Sobrien moves the computed address into the PC, so it must be the second one 98360484Sobrien in the sequence. The problem, however is that whilst little endian code 98460484Sobrien stores the instructions in HI then LOW order, big endian code does the 98589857Sobrien reverse. nickc@cygnus.com. */ 98660484Sobrien 98760484Sobrien#define LOW_HI_ORDER 0xF800F000 98860484Sobrien#define HI_LOW_ORDER 0xF000F800 98960484Sobrien 99060484Sobrienstatic insn32 991218822Sdiminsert_thumb_branch (insn32 br_insn, int rel_off) 99260484Sobrien{ 99360484Sobrien unsigned int low_bits; 99460484Sobrien unsigned int high_bits; 99560484Sobrien 996218822Sdim BFD_ASSERT ((rel_off & 1) != 1); 99760484Sobrien 998218822Sdim rel_off >>= 1; /* Half word aligned address. */ 999218822Sdim low_bits = rel_off & 0x000007FF; /* The bottom 11 bits. */ 1000218822Sdim high_bits = (rel_off >> 11) & 0x000007FF; /* The top 11 bits. */ 100160484Sobrien 100260484Sobrien if ((br_insn & LOW_HI_ORDER) == LOW_HI_ORDER) 100360484Sobrien br_insn = LOW_HI_ORDER | (low_bits << 16) | high_bits; 100460484Sobrien else if ((br_insn & HI_LOW_ORDER) == HI_LOW_ORDER) 100560484Sobrien br_insn = HI_LOW_ORDER | (high_bits << 16) | low_bits; 100660484Sobrien else 100789857Sobrien /* FIXME: the BFD library should never abort except for internal errors 100889857Sobrien - it should return an error status. */ 100989857Sobrien abort (); /* Error - not a valid branch instruction form. */ 101060484Sobrien 101160484Sobrien return br_insn; 101260484Sobrien} 101399461Sobrien 101460484Sobrien 101560484Sobrienstatic struct coff_link_hash_entry * 1016218822Sdimfind_thumb_glue (struct bfd_link_info *info, 1017218822Sdim const char *name, 1018218822Sdim bfd *input_bfd) 101960484Sobrien{ 102089857Sobrien char *tmp_name; 102189857Sobrien struct coff_link_hash_entry *myh; 102289857Sobrien bfd_size_type amt = strlen (name) + strlen (THUMB2ARM_GLUE_ENTRY_NAME) + 1; 102360484Sobrien 1024218822Sdim tmp_name = bfd_malloc (amt); 102560484Sobrien 102660484Sobrien BFD_ASSERT (tmp_name); 102760484Sobrien 102860484Sobrien sprintf (tmp_name, THUMB2ARM_GLUE_ENTRY_NAME, name); 102977298Sobrien 103060484Sobrien myh = coff_link_hash_lookup 1031130561Sobrien (coff_hash_table (info), tmp_name, FALSE, FALSE, TRUE); 103277298Sobrien 103360484Sobrien if (myh == NULL) 103460484Sobrien /* xgettext:c-format */ 1035218822Sdim _bfd_error_handler (_("%B: unable to find THUMB glue '%s' for `%s'"), 1036218822Sdim input_bfd, tmp_name, name); 103777298Sobrien 103860484Sobrien free (tmp_name); 103960484Sobrien 104060484Sobrien return myh; 104160484Sobrien} 104299461Sobrien#endif /* not ARM_WINCE */ 104360484Sobrien 104460484Sobrienstatic struct coff_link_hash_entry * 1045218822Sdimfind_arm_glue (struct bfd_link_info *info, 1046218822Sdim const char *name, 1047218822Sdim bfd *input_bfd) 104860484Sobrien{ 104989857Sobrien char *tmp_name; 105060484Sobrien struct coff_link_hash_entry * myh; 105189857Sobrien bfd_size_type amt = strlen (name) + strlen (ARM2THUMB_GLUE_ENTRY_NAME) + 1; 105260484Sobrien 1053218822Sdim tmp_name = bfd_malloc (amt); 105460484Sobrien 105560484Sobrien BFD_ASSERT (tmp_name); 105660484Sobrien 105760484Sobrien sprintf (tmp_name, ARM2THUMB_GLUE_ENTRY_NAME, name); 105877298Sobrien 105960484Sobrien myh = coff_link_hash_lookup 1060130561Sobrien (coff_hash_table (info), tmp_name, FALSE, FALSE, TRUE); 106160484Sobrien 106260484Sobrien if (myh == NULL) 106360484Sobrien /* xgettext:c-format */ 1064218822Sdim _bfd_error_handler (_("%B: unable to find ARM glue '%s' for `%s'"), 1065218822Sdim input_bfd, tmp_name, name); 106677298Sobrien 106760484Sobrien free (tmp_name); 106860484Sobrien 106960484Sobrien return myh; 107060484Sobrien} 107160484Sobrien 107260484Sobrien/* 107360484Sobrien ARM->Thumb glue: 107460484Sobrien 107560484Sobrien .arm 107660484Sobrien __func_from_arm: 107760484Sobrien ldr r12, __func_addr 107860484Sobrien bx r12 107960484Sobrien __func_addr: 108060484Sobrien .word func @ behave as if you saw a ARM_32 reloc 108160484Sobrien*/ 108260484Sobrien 108360484Sobrien#define ARM2THUMB_GLUE_SIZE 12 108460484Sobrienstatic const insn32 a2t1_ldr_insn = 0xe59fc000; 108560484Sobrienstatic const insn32 a2t2_bx_r12_insn = 0xe12fff1c; 108660484Sobrienstatic const insn32 a2t3_func_addr_insn = 0x00000001; 108760484Sobrien 108860484Sobrien/* 108960484Sobrien Thumb->ARM: Thumb->(non-interworking aware) ARM 109060484Sobrien 109160484Sobrien .thumb .thumb 109260484Sobrien .align 2 .align 2 109360484Sobrien __func_from_thumb: __func_from_thumb: 109460484Sobrien bx pc push {r6, lr} 109560484Sobrien nop ldr r6, __func_addr 109660484Sobrien .arm mov lr, pc 109760484Sobrien __func_change_to_arm: bx r6 109860484Sobrien b func .arm 109960484Sobrien __func_back_to_thumb: 110060484Sobrien ldmia r13! {r6, lr} 110160484Sobrien bx lr 110260484Sobrien __func_addr: 110377298Sobrien .word func 110460484Sobrien*/ 110560484Sobrien 110660484Sobrien#define THUMB2ARM_GLUE_SIZE (globals->support_old_code ? 20 : 8) 1107218822Sdim#ifndef ARM_WINCE 110860484Sobrienstatic const insn16 t2a1_bx_pc_insn = 0x4778; 110960484Sobrienstatic const insn16 t2a2_noop_insn = 0x46c0; 111060484Sobrienstatic const insn32 t2a3_b_insn = 0xea000000; 111160484Sobrien 111260484Sobrienstatic const insn16 t2a1_push_insn = 0xb540; 111360484Sobrienstatic const insn16 t2a2_ldr_insn = 0x4e03; 111460484Sobrienstatic const insn16 t2a3_mov_insn = 0x46fe; 111560484Sobrienstatic const insn16 t2a4_bx_insn = 0x4730; 111660484Sobrienstatic const insn32 t2a5_pop_insn = 0xe8bd4040; 111760484Sobrienstatic const insn32 t2a6_bx_insn = 0xe12fff1e; 1118218822Sdim#endif 111960484Sobrien 112060484Sobrien/* TODO: 112160484Sobrien We should really create new local (static) symbols in destination 112260484Sobrien object for each stub we create. We should also create local 112360484Sobrien (static) symbols within the stubs when switching between ARM and 112460484Sobrien Thumb code. This will ensure that the debugger and disassembler 112560484Sobrien can present a better view of stubs. 112660484Sobrien 112760484Sobrien We can treat stubs like literal sections, and for the THUMB9 ones 112860484Sobrien (short addressing range) we should be able to insert the stubs 112960484Sobrien between sections. i.e. the simplest approach (since relocations 113060484Sobrien are done on a section basis) is to dump the stubs at the end of 113160484Sobrien processing a section. That way we can always try and minimise the 113260484Sobrien offset to and from a stub. However, this does not map well onto 113360484Sobrien the way that the linker/BFD does its work: mapping all input 113460484Sobrien sections to output sections via the linker script before doing 113560484Sobrien all the processing. 113660484Sobrien 113760484Sobrien Unfortunately it may be easier to just to disallow short range 113860484Sobrien Thumb->ARM stubs (i.e. no conditional inter-working branches, 113960484Sobrien only branch-and-link (BL) calls. This will simplify the processing 114060484Sobrien since we can then put all of the stubs into their own section. 114160484Sobrien 114260484Sobrien TODO: 114360484Sobrien On a different subject, rather than complaining when a 114460484Sobrien branch cannot fit in the number of bits available for the 114560484Sobrien instruction we should generate a trampoline stub (needed to 114660484Sobrien address the complete 32bit address space). */ 114760484Sobrien 114877298Sobrien/* The standard COFF backend linker does not cope with the special 114960484Sobrien Thumb BRANCH23 relocation. The alternative would be to split the 115060484Sobrien BRANCH23 into seperate HI23 and LO23 relocations. However, it is a 115177298Sobrien bit simpler simply providing our own relocation driver. */ 115260484Sobrien 115360484Sobrien/* The reloc processing routine for the ARM/Thumb COFF linker. NOTE: 115460484Sobrien This code is a very slightly modified copy of 115560484Sobrien _bfd_coff_generic_relocate_section. It would be a much more 115660484Sobrien maintainable solution to have a MACRO that could be expanded within 115760484Sobrien _bfd_coff_generic_relocate_section that would only be provided for 115860484Sobrien ARM/Thumb builds. It is only the code marked THUMBEXTENSION that 115960484Sobrien is different from the original. */ 116060484Sobrien 1161130561Sobrienstatic bfd_boolean 1162218822Sdimcoff_arm_relocate_section (bfd *output_bfd, 1163218822Sdim struct bfd_link_info *info, 1164218822Sdim bfd *input_bfd, 1165218822Sdim asection *input_section, 1166218822Sdim bfd_byte *contents, 1167218822Sdim struct internal_reloc *relocs, 1168218822Sdim struct internal_syment *syms, 1169218822Sdim asection **sections) 117060484Sobrien{ 117160484Sobrien struct internal_reloc * rel; 117260484Sobrien struct internal_reloc * relend; 1173218822Sdim#ifndef ARM_WINCE 1174218822Sdim bfd_vma high_address = bfd_get_section_limit (input_bfd, input_section); 1175218822Sdim#endif 117660484Sobrien 117760484Sobrien rel = relocs; 117860484Sobrien relend = rel + input_section->reloc_count; 117960484Sobrien 118060484Sobrien for (; rel < relend; rel++) 118160484Sobrien { 118260484Sobrien int done = 0; 118360484Sobrien long symndx; 118460484Sobrien struct coff_link_hash_entry * h; 118560484Sobrien struct internal_syment * sym; 118660484Sobrien bfd_vma addend; 118760484Sobrien bfd_vma val; 118860484Sobrien reloc_howto_type * howto; 118960484Sobrien bfd_reloc_status_type rstat; 119060484Sobrien bfd_vma h_val; 119160484Sobrien 119260484Sobrien symndx = rel->r_symndx; 119360484Sobrien 119460484Sobrien if (symndx == -1) 119560484Sobrien { 119660484Sobrien h = NULL; 119760484Sobrien sym = NULL; 119860484Sobrien } 119960484Sobrien else 120077298Sobrien { 120160484Sobrien h = obj_coff_sym_hashes (input_bfd)[symndx]; 120260484Sobrien sym = syms + symndx; 120360484Sobrien } 120460484Sobrien 120560484Sobrien /* COFF treats common symbols in one of two ways. Either the 120660484Sobrien size of the symbol is included in the section contents, or it 120760484Sobrien is not. We assume that the size is not included, and force 120860484Sobrien the rtype_to_howto function to adjust the addend as needed. */ 120960484Sobrien 121060484Sobrien if (sym != NULL && sym->n_scnum != 0) 121160484Sobrien addend = - sym->n_value; 121260484Sobrien else 121360484Sobrien addend = 0; 121460484Sobrien 121560484Sobrien howto = coff_rtype_to_howto (input_bfd, input_section, rel, h, 121660484Sobrien sym, &addend); 121760484Sobrien if (howto == NULL) 1218130561Sobrien return FALSE; 121960484Sobrien 122060484Sobrien /* The relocation_section function will skip pcrel_offset relocs 1221130561Sobrien when doing a relocatable link. However, we want to convert 1222130561Sobrien ARM_26 to ARM_26D relocs if possible. We return a fake howto in 122360484Sobrien this case without pcrel_offset set, and adjust the addend to 1224130561Sobrien compensate. 'partial_inplace' is also set, since we want 'done' 1225130561Sobrien relocations to be reflected in section's data. */ 122660484Sobrien if (rel->r_type == ARM_26 122760484Sobrien && h != NULL 1228130561Sobrien && info->relocatable 122960484Sobrien && (h->root.type == bfd_link_hash_defined 123060484Sobrien || h->root.type == bfd_link_hash_defweak) 123189857Sobrien && (h->root.u.def.section->output_section 123289857Sobrien == input_section->output_section)) 123360484Sobrien { 123477298Sobrien static reloc_howto_type fake_arm26_reloc = 123560484Sobrien HOWTO (ARM_26, 123660484Sobrien 2, 123760484Sobrien 2, 123860484Sobrien 24, 1239130561Sobrien TRUE, 124060484Sobrien 0, 124160484Sobrien complain_overflow_signed, 124260484Sobrien aoutarm_fix_pcrel_26 , 124360484Sobrien "ARM_26", 1244130561Sobrien TRUE, 124560484Sobrien 0x00ffffff, 124677298Sobrien 0x00ffffff, 1247130561Sobrien FALSE); 124860484Sobrien 124960484Sobrien addend -= rel->r_vaddr - input_section->vma; 1250130561Sobrien#ifdef ARM_WINCE 1251130561Sobrien /* FIXME: I don't know why, but the hack is necessary for correct 1252218822Sdim generation of bl's instruction offset. */ 1253130561Sobrien addend -= 8; 1254130561Sobrien#endif 1255218822Sdim howto = & fake_arm26_reloc; 125660484Sobrien } 125760484Sobrien 125860484Sobrien#ifdef ARM_WINCE 125960484Sobrien /* MS ARM-CE makes the reloc relative to the opcode's pc, not 126077298Sobrien the next opcode's pc, so is off by one. */ 1261130561Sobrien if (howto->pc_relative && !info->relocatable) 126260484Sobrien addend -= 8; 126360484Sobrien#endif 126477298Sobrien 1265130561Sobrien /* If we are doing a relocatable link, then we can just ignore 126660484Sobrien a PC relative reloc that is pcrel_offset. It will already 1267130561Sobrien have the correct value. If this is not a relocatable link, 126860484Sobrien then we should ignore the symbol value. */ 126960484Sobrien if (howto->pc_relative && howto->pcrel_offset) 127060484Sobrien { 1271130561Sobrien if (info->relocatable) 127260484Sobrien continue; 127378828Sobrien /* FIXME - it is not clear which targets need this next test 127478828Sobrien and which do not. It is known that it is needed for the 127589857Sobrien VxWorks and EPOC-PE targets, but it is also known that it 1276130561Sobrien was suppressed for other ARM targets. This ought to be 127789857Sobrien sorted out one day. */ 127889857Sobrien#ifdef ARM_COFF_BUGFIX 127978828Sobrien /* We must not ignore the symbol value. If the symbol is 128078828Sobrien within the same section, the relocation should have already 128178828Sobrien been fixed, but if it is not, we'll be handed a reloc into 128278828Sobrien the beginning of the symbol's section, so we must not cancel 128378828Sobrien out the symbol's value, otherwise we'll be adding it in 128478828Sobrien twice. */ 128560484Sobrien if (sym != NULL && sym->n_scnum != 0) 128660484Sobrien addend += sym->n_value; 128777298Sobrien#endif 128860484Sobrien } 128960484Sobrien 129060484Sobrien val = 0; 129160484Sobrien 129260484Sobrien if (h == NULL) 129360484Sobrien { 129460484Sobrien asection *sec; 129560484Sobrien 129660484Sobrien if (symndx == -1) 129760484Sobrien { 129860484Sobrien sec = bfd_abs_section_ptr; 129960484Sobrien val = 0; 130060484Sobrien } 130160484Sobrien else 130260484Sobrien { 130360484Sobrien sec = sections[symndx]; 130460484Sobrien val = (sec->output_section->vma 130560484Sobrien + sec->output_offset 130660484Sobrien + sym->n_value 130760484Sobrien - sec->vma); 130860484Sobrien } 130960484Sobrien } 131060484Sobrien else 131160484Sobrien { 131260484Sobrien /* We don't output the stubs if we are generating a 131360484Sobrien relocatable output file, since we may as well leave the 131460484Sobrien stub generation to the final linker pass. If we fail to 131560484Sobrien verify that the name is defined, we'll try to build stubs 131677298Sobrien for an undefined name... */ 1317130561Sobrien if (! info->relocatable 131860484Sobrien && ( h->root.type == bfd_link_hash_defined 131960484Sobrien || h->root.type == bfd_link_hash_defweak)) 132060484Sobrien { 132160484Sobrien asection * h_sec = h->root.u.def.section; 132260484Sobrien const char * name = h->root.root.string; 132377298Sobrien 132460484Sobrien /* h locates the symbol referenced in the reloc. */ 132560484Sobrien h_val = (h->root.u.def.value 132660484Sobrien + h_sec->output_section->vma 132760484Sobrien + h_sec->output_offset); 132860484Sobrien 132960484Sobrien if (howto->type == ARM_26) 133060484Sobrien { 133160484Sobrien if ( h->class == C_THUMBSTATFUNC 133260484Sobrien || h->class == C_THUMBEXTFUNC) 133360484Sobrien { 133489857Sobrien /* Arm code calling a Thumb function. */ 133560484Sobrien unsigned long int tmp; 133689857Sobrien bfd_vma my_offset; 133760484Sobrien asection * s; 133860484Sobrien long int ret_offset; 133977298Sobrien struct coff_link_hash_entry * myh; 134060484Sobrien struct coff_arm_link_hash_table * globals; 134177298Sobrien 134260484Sobrien myh = find_arm_glue (info, name, input_bfd); 134360484Sobrien if (myh == NULL) 1344130561Sobrien return FALSE; 134560484Sobrien 134660484Sobrien globals = coff_arm_hash_table (info); 134760484Sobrien 134860484Sobrien BFD_ASSERT (globals != NULL); 134960484Sobrien BFD_ASSERT (globals->bfd_of_glue_owner != NULL); 135077298Sobrien 135160484Sobrien my_offset = myh->root.u.def.value; 135277298Sobrien 135377298Sobrien s = bfd_get_section_by_name (globals->bfd_of_glue_owner, 135460484Sobrien ARM2THUMB_GLUE_SECTION_NAME); 135560484Sobrien BFD_ASSERT (s != NULL); 135660484Sobrien BFD_ASSERT (s->contents != NULL); 135760484Sobrien BFD_ASSERT (s->output_section != NULL); 135860484Sobrien 135960484Sobrien if ((my_offset & 0x01) == 0x01) 136060484Sobrien { 136160484Sobrien if (h_sec->owner != NULL 136260484Sobrien && INTERWORK_SET (h_sec->owner) 136360484Sobrien && ! INTERWORK_FLAG (h_sec->owner)) 1364218822Sdim _bfd_error_handler 1365218822Sdim /* xgettext:c-format */ 1366218822Sdim (_("%B(%s): warning: interworking not enabled.\n" 1367218822Sdim " first occurrence: %B: arm call to thumb"), 1368218822Sdim h_sec->owner, input_bfd, name); 136960484Sobrien 137060484Sobrien --my_offset; 137160484Sobrien myh->root.u.def.value = my_offset; 137260484Sobrien 137389857Sobrien bfd_put_32 (output_bfd, (bfd_vma) a2t1_ldr_insn, 137460484Sobrien s->contents + my_offset); 137577298Sobrien 137689857Sobrien bfd_put_32 (output_bfd, (bfd_vma) a2t2_bx_r12_insn, 137760484Sobrien s->contents + my_offset + 4); 137877298Sobrien 137960484Sobrien /* It's a thumb address. Add the low order bit. */ 138060484Sobrien bfd_put_32 (output_bfd, h_val | a2t3_func_addr_insn, 138160484Sobrien s->contents + my_offset + 8); 138260484Sobrien 138360484Sobrien if (info->base_file) 138477298Sobrien arm_emit_base_file_entry (info, output_bfd, s, 138589857Sobrien my_offset + 8); 138660484Sobrien 138760484Sobrien } 138860484Sobrien 138960484Sobrien BFD_ASSERT (my_offset <= globals->arm_glue_size); 139060484Sobrien 139160484Sobrien tmp = bfd_get_32 (input_bfd, contents + rel->r_vaddr 139260484Sobrien - input_section->vma); 139377298Sobrien 139460484Sobrien tmp = tmp & 0xFF000000; 139560484Sobrien 139677298Sobrien /* Somehow these are both 4 too far, so subtract 8. */ 139760484Sobrien ret_offset = 139860484Sobrien s->output_offset 139977298Sobrien + my_offset 140060484Sobrien + s->output_section->vma 140160484Sobrien - (input_section->output_offset 140277298Sobrien + input_section->output_section->vma 140360484Sobrien + rel->r_vaddr) 140460484Sobrien - 8; 140560484Sobrien 140660484Sobrien tmp = tmp | ((ret_offset >> 2) & 0x00FFFFFF); 140777298Sobrien 140889857Sobrien bfd_put_32 (output_bfd, (bfd_vma) tmp, 140989857Sobrien contents + rel->r_vaddr - input_section->vma); 141060484Sobrien done = 1; 141160484Sobrien } 141260484Sobrien } 141377298Sobrien 141460484Sobrien#ifndef ARM_WINCE 141589857Sobrien /* Note: We used to check for ARM_THUMB9 and ARM_THUMB12. */ 141660484Sobrien else if (howto->type == ARM_THUMB23) 141760484Sobrien { 141877298Sobrien if ( h->class == C_EXT 141960484Sobrien || h->class == C_STAT 142060484Sobrien || h->class == C_LABEL) 142160484Sobrien { 1422218822Sdim /* Thumb code calling an ARM function. */ 142360484Sobrien asection * s = 0; 142489857Sobrien bfd_vma my_offset; 142560484Sobrien unsigned long int tmp; 142660484Sobrien long int ret_offset; 142760484Sobrien struct coff_link_hash_entry * myh; 142860484Sobrien struct coff_arm_link_hash_table * globals; 142960484Sobrien 143060484Sobrien myh = find_thumb_glue (info, name, input_bfd); 143160484Sobrien if (myh == NULL) 1432130561Sobrien return FALSE; 143360484Sobrien 143460484Sobrien globals = coff_arm_hash_table (info); 143577298Sobrien 143660484Sobrien BFD_ASSERT (globals != NULL); 143760484Sobrien BFD_ASSERT (globals->bfd_of_glue_owner != NULL); 143877298Sobrien 143960484Sobrien my_offset = myh->root.u.def.value; 144077298Sobrien 144177298Sobrien s = bfd_get_section_by_name (globals->bfd_of_glue_owner, 144260484Sobrien THUMB2ARM_GLUE_SECTION_NAME); 144377298Sobrien 144460484Sobrien BFD_ASSERT (s != NULL); 144560484Sobrien BFD_ASSERT (s->contents != NULL); 144660484Sobrien BFD_ASSERT (s->output_section != NULL); 144777298Sobrien 144860484Sobrien if ((my_offset & 0x01) == 0x01) 144960484Sobrien { 145060484Sobrien if (h_sec->owner != NULL 145160484Sobrien && INTERWORK_SET (h_sec->owner) 145260484Sobrien && ! INTERWORK_FLAG (h_sec->owner) 145360484Sobrien && ! globals->support_old_code) 1454218822Sdim _bfd_error_handler 1455218822Sdim /* xgettext:c-format */ 1456218822Sdim (_("%B(%s): warning: interworking not enabled.\n" 1457218822Sdim " first occurrence: %B: thumb call to arm\n" 1458218822Sdim " consider relinking with --support-old-code enabled"), 1459218822Sdim h_sec->owner, input_bfd, name); 146077298Sobrien 146160484Sobrien -- my_offset; 146260484Sobrien myh->root.u.def.value = my_offset; 146360484Sobrien 146460484Sobrien if (globals->support_old_code) 146560484Sobrien { 146689857Sobrien bfd_put_16 (output_bfd, (bfd_vma) t2a1_push_insn, 146760484Sobrien s->contents + my_offset); 146877298Sobrien 146989857Sobrien bfd_put_16 (output_bfd, (bfd_vma) t2a2_ldr_insn, 147060484Sobrien s->contents + my_offset + 2); 147160484Sobrien 147289857Sobrien bfd_put_16 (output_bfd, (bfd_vma) t2a3_mov_insn, 147360484Sobrien s->contents + my_offset + 4); 147460484Sobrien 147589857Sobrien bfd_put_16 (output_bfd, (bfd_vma) t2a4_bx_insn, 147660484Sobrien s->contents + my_offset + 6); 147777298Sobrien 147889857Sobrien bfd_put_32 (output_bfd, (bfd_vma) t2a5_pop_insn, 147960484Sobrien s->contents + my_offset + 8); 148077298Sobrien 148189857Sobrien bfd_put_32 (output_bfd, (bfd_vma) t2a6_bx_insn, 148260484Sobrien s->contents + my_offset + 12); 148377298Sobrien 148460484Sobrien /* Store the address of the function in the last word of the stub. */ 148560484Sobrien bfd_put_32 (output_bfd, h_val, 148660484Sobrien s->contents + my_offset + 16); 148760484Sobrien 148860484Sobrien if (info->base_file) 148989857Sobrien arm_emit_base_file_entry (info, output_bfd, s, 149089857Sobrien my_offset + 16); 149160484Sobrien } 149260484Sobrien else 149360484Sobrien { 149489857Sobrien bfd_put_16 (output_bfd, (bfd_vma) t2a1_bx_pc_insn, 149560484Sobrien s->contents + my_offset); 149677298Sobrien 149789857Sobrien bfd_put_16 (output_bfd, (bfd_vma) t2a2_noop_insn, 149860484Sobrien s->contents + my_offset + 2); 149977298Sobrien 150060484Sobrien ret_offset = 1501218822Sdim /* Address of destination of the stub. */ 1502218822Sdim ((bfd_signed_vma) h_val) 150360484Sobrien - ((bfd_signed_vma) 1504218822Sdim /* Offset from the start of the current section to the start of the stubs. */ 1505218822Sdim (s->output_offset 1506218822Sdim /* Offset of the start of this stub from the start of the stubs. */ 1507218822Sdim + my_offset 1508218822Sdim /* Address of the start of the current section. */ 1509218822Sdim + s->output_section->vma) 1510218822Sdim /* The branch instruction is 4 bytes into the stub. */ 1511218822Sdim + 4 1512218822Sdim /* ARM branches work from the pc of the instruction + 8. */ 1513218822Sdim + 8); 151477298Sobrien 151560484Sobrien bfd_put_32 (output_bfd, 151689857Sobrien (bfd_vma) t2a3_b_insn | ((ret_offset >> 2) & 0x00FFFFFF), 151760484Sobrien s->contents + my_offset + 4); 151860484Sobrien 151960484Sobrien } 152060484Sobrien } 152160484Sobrien 152260484Sobrien BFD_ASSERT (my_offset <= globals->thumb_glue_size); 152360484Sobrien 152460484Sobrien /* Now go back and fix up the original BL insn to point 152560484Sobrien to here. */ 152660484Sobrien ret_offset = 152760484Sobrien s->output_offset 152860484Sobrien + my_offset 152960484Sobrien - (input_section->output_offset 153060484Sobrien + rel->r_vaddr) 153160484Sobrien -4; 153277298Sobrien 153360484Sobrien tmp = bfd_get_32 (input_bfd, contents + rel->r_vaddr 153460484Sobrien - input_section->vma); 153560484Sobrien 153660484Sobrien bfd_put_32 (output_bfd, 153789857Sobrien (bfd_vma) insert_thumb_branch (tmp, 153889857Sobrien ret_offset), 153989857Sobrien contents + rel->r_vaddr - input_section->vma); 154077298Sobrien 154160484Sobrien done = 1; 154260484Sobrien } 154360484Sobrien } 154460484Sobrien#endif 154560484Sobrien } 154677298Sobrien 154760484Sobrien /* If the relocation type and destination symbol does not 154860484Sobrien fall into one of the above categories, then we can just 154977298Sobrien perform a direct link. */ 155060484Sobrien 155160484Sobrien if (done) 155260484Sobrien rstat = bfd_reloc_ok; 155377298Sobrien else 155460484Sobrien if ( h->root.type == bfd_link_hash_defined 155560484Sobrien || h->root.type == bfd_link_hash_defweak) 155660484Sobrien { 155760484Sobrien asection *sec; 155860484Sobrien 155960484Sobrien sec = h->root.u.def.section; 156060484Sobrien val = (h->root.u.def.value 156160484Sobrien + sec->output_section->vma 156260484Sobrien + sec->output_offset); 156360484Sobrien } 156460484Sobrien 1565130561Sobrien else if (! info->relocatable) 156660484Sobrien { 156760484Sobrien if (! ((*info->callbacks->undefined_symbol) 156860484Sobrien (info, h->root.root.string, input_bfd, input_section, 1569130561Sobrien rel->r_vaddr - input_section->vma, TRUE))) 1570130561Sobrien return FALSE; 157160484Sobrien } 157260484Sobrien } 157360484Sobrien 157460484Sobrien if (info->base_file) 157560484Sobrien { 157677298Sobrien /* Emit a reloc if the backend thinks it needs it. */ 157760484Sobrien if (sym && pe_data(output_bfd)->in_reloc_p(output_bfd, howto)) 157889857Sobrien arm_emit_base_file_entry (info, output_bfd, input_section, 157989857Sobrien rel->r_vaddr); 158060484Sobrien } 158177298Sobrien 158260484Sobrien if (done) 158360484Sobrien rstat = bfd_reloc_ok; 158460484Sobrien#ifndef ARM_WINCE 1585218822Sdim /* Only perform this fix during the final link, not a relocatable link. */ 1586130561Sobrien else if (! info->relocatable 158760484Sobrien && howto->type == ARM_THUMB23) 158860484Sobrien { 158960484Sobrien /* This is pretty much a copy of what the default 159060484Sobrien _bfd_final_link_relocate and _bfd_relocate_contents 159160484Sobrien routines do to perform a relocation, with special 159260484Sobrien processing for the split addressing of the Thumb BL 159360484Sobrien instruction. Again, it would probably be simpler adding a 159460484Sobrien ThumbBRANCH23 specific macro expansion into the default 159560484Sobrien code. */ 159677298Sobrien 159760484Sobrien bfd_vma address = rel->r_vaddr - input_section->vma; 159877298Sobrien 1599218822Sdim if (address > high_address) 160060484Sobrien rstat = bfd_reloc_outofrange; 160160484Sobrien else 160260484Sobrien { 1603130561Sobrien bfd_vma relocation = val + addend; 1604130561Sobrien int size = bfd_get_reloc_size (howto); 1605130561Sobrien bfd_boolean overflow = FALSE; 1606130561Sobrien bfd_byte *location = contents + address; 1607130561Sobrien bfd_vma x = bfd_get_32 (input_bfd, location); 1608130561Sobrien bfd_vma src_mask = 0x007FFFFE; 1609130561Sobrien bfd_signed_vma reloc_signed_max = (1 << (howto->bitsize - 1)) - 1; 1610130561Sobrien bfd_signed_vma reloc_signed_min = ~reloc_signed_max; 1611130561Sobrien bfd_vma check; 1612130561Sobrien bfd_signed_vma signed_check; 1613130561Sobrien bfd_vma add; 1614130561Sobrien bfd_signed_vma signed_add; 161560484Sobrien 161660484Sobrien BFD_ASSERT (size == 4); 161777298Sobrien 161878828Sobrien /* howto->pc_relative should be TRUE for type 14 BRANCH23. */ 161960484Sobrien relocation -= (input_section->output_section->vma 162060484Sobrien + input_section->output_offset); 162177298Sobrien 162278828Sobrien /* howto->pcrel_offset should be TRUE for type 14 BRANCH23. */ 162360484Sobrien relocation -= address; 162477298Sobrien 162577298Sobrien /* No need to negate the relocation with BRANCH23. */ 162660484Sobrien /* howto->complain_on_overflow == complain_overflow_signed for BRANCH23. */ 162760484Sobrien /* howto->rightshift == 1 */ 162878828Sobrien 162960484Sobrien /* Drop unwanted bits from the value we are relocating to. */ 163060484Sobrien check = relocation >> howto->rightshift; 163177298Sobrien 163260484Sobrien /* If this is a signed value, the rightshift just dropped 163360484Sobrien leading 1 bits (assuming twos complement). */ 163460484Sobrien if ((bfd_signed_vma) relocation >= 0) 163560484Sobrien signed_check = check; 163660484Sobrien else 163760484Sobrien signed_check = (check 163860484Sobrien | ((bfd_vma) - 1 163960484Sobrien & ~((bfd_vma) - 1 >> howto->rightshift))); 164077298Sobrien 164160484Sobrien /* Get the value from the object file. */ 164260484Sobrien if (bfd_big_endian (input_bfd)) 164378828Sobrien add = (((x) & 0x07ff0000) >> 4) | (((x) & 0x7ff) << 1); 164460484Sobrien else 164578828Sobrien add = ((((x) & 0x7ff) << 12) | (((x) & 0x07ff0000) >> 15)); 164660484Sobrien 164760484Sobrien /* Get the value from the object file with an appropriate sign. 164860484Sobrien The expression involving howto->src_mask isolates the upper 164960484Sobrien bit of src_mask. If that bit is set in the value we are 165060484Sobrien adding, it is negative, and we subtract out that number times 165160484Sobrien two. If src_mask includes the highest possible bit, then we 165260484Sobrien can not get the upper bit, but that does not matter since 165360484Sobrien signed_add needs no adjustment to become negative in that 165460484Sobrien case. */ 165560484Sobrien signed_add = add; 165677298Sobrien 165760484Sobrien if ((add & (((~ src_mask) >> 1) & src_mask)) != 0) 165860484Sobrien signed_add -= (((~ src_mask) >> 1) & src_mask) << 1; 165977298Sobrien 166078828Sobrien /* howto->bitpos == 0 */ 166160484Sobrien /* Add the value from the object file, shifted so that it is a 166260484Sobrien straight number. */ 166360484Sobrien signed_check += signed_add; 166478828Sobrien relocation += signed_add; 166560484Sobrien 166660484Sobrien BFD_ASSERT (howto->complain_on_overflow == complain_overflow_signed); 166760484Sobrien 166860484Sobrien /* Assumes two's complement. */ 166960484Sobrien if ( signed_check > reloc_signed_max 167060484Sobrien || signed_check < reloc_signed_min) 1671130561Sobrien overflow = TRUE; 167277298Sobrien 1673104834Sobrien /* Put the relocation into the correct bits. 1674104834Sobrien For a BLX instruction, make sure that the relocation is rounded up 1675104834Sobrien to a word boundary. This follows the semantics of the instruction 1676104834Sobrien which specifies that bit 1 of the target address will come from bit 1677104834Sobrien 1 of the base address. */ 167860484Sobrien if (bfd_big_endian (input_bfd)) 1679104834Sobrien { 1680104834Sobrien if ((x & 0x1800) == 0x0800 && (relocation & 0x02)) 1681104834Sobrien relocation += 2; 1682104834Sobrien relocation = (((relocation & 0xffe) >> 1) | ((relocation << 4) & 0x07ff0000)); 1683104834Sobrien } 168460484Sobrien else 1685104834Sobrien { 1686104834Sobrien if ((x & 0x18000000) == 0x08000000 && (relocation & 0x02)) 1687104834Sobrien relocation += 2; 1688104834Sobrien relocation = (((relocation & 0xffe) << 15) | ((relocation >> 12) & 0x7ff)); 1689104834Sobrien } 169077298Sobrien 169178828Sobrien /* Add the relocation to the correct bits of X. */ 169260484Sobrien x = ((x & ~howto->dst_mask) | relocation); 169360484Sobrien 169478828Sobrien /* Put the relocated value back in the object file. */ 169560484Sobrien bfd_put_32 (input_bfd, x, location); 169660484Sobrien 169760484Sobrien rstat = overflow ? bfd_reloc_overflow : bfd_reloc_ok; 169860484Sobrien } 169960484Sobrien } 170060484Sobrien#endif 170160484Sobrien else 1702130561Sobrien if (info->relocatable && ! howto->partial_inplace) 1703130561Sobrien rstat = bfd_reloc_ok; 1704130561Sobrien else 1705130561Sobrien rstat = _bfd_final_link_relocate (howto, input_bfd, input_section, 1706130561Sobrien contents, 1707130561Sobrien rel->r_vaddr - input_section->vma, 1708130561Sobrien val, addend); 1709218822Sdim /* Only perform this fix during the final link, not a relocatable link. */ 1710130561Sobrien if (! info->relocatable 171160484Sobrien && (rel->r_type == ARM_32 || rel->r_type == ARM_RVA32)) 171260484Sobrien { 171360484Sobrien /* Determine if we need to set the bottom bit of a relocated address 171460484Sobrien because the address is the address of a Thumb code symbol. */ 1715130561Sobrien int patchit = FALSE; 171677298Sobrien 171760484Sobrien if (h != NULL 171860484Sobrien && ( h->class == C_THUMBSTATFUNC 171960484Sobrien || h->class == C_THUMBEXTFUNC)) 172060484Sobrien { 1721130561Sobrien patchit = TRUE; 172260484Sobrien } 172360484Sobrien else if (sym != NULL 172460484Sobrien && sym->n_scnum > N_UNDEF) 172560484Sobrien { 172660484Sobrien /* No hash entry - use the symbol instead. */ 172760484Sobrien if ( sym->n_sclass == C_THUMBSTATFUNC 172860484Sobrien || sym->n_sclass == C_THUMBEXTFUNC) 1729130561Sobrien patchit = TRUE; 173060484Sobrien } 173160484Sobrien 173260484Sobrien if (patchit) 173360484Sobrien { 173460484Sobrien bfd_byte * location = contents + rel->r_vaddr - input_section->vma; 173560484Sobrien bfd_vma x = bfd_get_32 (input_bfd, location); 173660484Sobrien 173760484Sobrien bfd_put_32 (input_bfd, x | 1, location); 173860484Sobrien } 173960484Sobrien } 174077298Sobrien 174160484Sobrien switch (rstat) 174260484Sobrien { 174360484Sobrien default: 174460484Sobrien abort (); 174560484Sobrien case bfd_reloc_ok: 174660484Sobrien break; 174760484Sobrien case bfd_reloc_outofrange: 174860484Sobrien (*_bfd_error_handler) 1749218822Sdim (_("%B: bad reloc address 0x%lx in section `%A'"), 1750218822Sdim input_bfd, input_section, (unsigned long) rel->r_vaddr); 1751130561Sobrien return FALSE; 175260484Sobrien case bfd_reloc_overflow: 175360484Sobrien { 175460484Sobrien const char *name; 175560484Sobrien char buf[SYMNMLEN + 1]; 175660484Sobrien 175760484Sobrien if (symndx == -1) 175860484Sobrien name = "*ABS*"; 175960484Sobrien else if (h != NULL) 1760218822Sdim name = NULL; 176160484Sobrien else 176260484Sobrien { 176360484Sobrien name = _bfd_coff_internal_syment_name (input_bfd, sym, buf); 176460484Sobrien if (name == NULL) 1765130561Sobrien return FALSE; 176660484Sobrien } 176760484Sobrien 176860484Sobrien if (! ((*info->callbacks->reloc_overflow) 1769218822Sdim (info, (h ? &h->root : NULL), name, howto->name, 1770218822Sdim (bfd_vma) 0, input_bfd, input_section, 1771218822Sdim rel->r_vaddr - input_section->vma))) 1772130561Sobrien return FALSE; 177360484Sobrien } 177460484Sobrien } 177560484Sobrien } 177660484Sobrien 1777130561Sobrien return TRUE; 177860484Sobrien} 177960484Sobrien 178060484Sobrien#ifndef COFF_IMAGE_WITH_PE 178160484Sobrien 1782130561Sobrienbfd_boolean 1783218822Sdimbfd_arm_allocate_interworking_sections (struct bfd_link_info * info) 178460484Sobrien{ 178560484Sobrien asection * s; 178660484Sobrien bfd_byte * foo; 178760484Sobrien struct coff_arm_link_hash_table * globals; 178860484Sobrien 178960484Sobrien globals = coff_arm_hash_table (info); 179077298Sobrien 179160484Sobrien BFD_ASSERT (globals != NULL); 179260484Sobrien 179360484Sobrien if (globals->arm_glue_size != 0) 179460484Sobrien { 179560484Sobrien BFD_ASSERT (globals->bfd_of_glue_owner != NULL); 179677298Sobrien 179760484Sobrien s = bfd_get_section_by_name 179860484Sobrien (globals->bfd_of_glue_owner, ARM2THUMB_GLUE_SECTION_NAME); 179960484Sobrien 180060484Sobrien BFD_ASSERT (s != NULL); 180177298Sobrien 1802218822Sdim foo = bfd_alloc (globals->bfd_of_glue_owner, globals->arm_glue_size); 180377298Sobrien 1804218822Sdim s->size = globals->arm_glue_size; 180560484Sobrien s->contents = foo; 180660484Sobrien } 180760484Sobrien 180860484Sobrien if (globals->thumb_glue_size != 0) 180960484Sobrien { 181060484Sobrien BFD_ASSERT (globals->bfd_of_glue_owner != NULL); 181177298Sobrien 181260484Sobrien s = bfd_get_section_by_name 181360484Sobrien (globals->bfd_of_glue_owner, THUMB2ARM_GLUE_SECTION_NAME); 181460484Sobrien 181560484Sobrien BFD_ASSERT (s != NULL); 181677298Sobrien 1817218822Sdim foo = bfd_alloc (globals->bfd_of_glue_owner, globals->thumb_glue_size); 181877298Sobrien 1819218822Sdim s->size = globals->thumb_glue_size; 182060484Sobrien s->contents = foo; 182160484Sobrien } 182260484Sobrien 1823130561Sobrien return TRUE; 182460484Sobrien} 182560484Sobrien 182660484Sobrienstatic void 1827218822Sdimrecord_arm_to_thumb_glue (struct bfd_link_info * info, 1828218822Sdim struct coff_link_hash_entry * h) 182960484Sobrien{ 183060484Sobrien const char * name = h->root.root.string; 183160484Sobrien register asection * s; 183260484Sobrien char * tmp_name; 183360484Sobrien struct coff_link_hash_entry * myh; 1834107492Sobrien struct bfd_link_hash_entry * bh; 183560484Sobrien struct coff_arm_link_hash_table * globals; 183689857Sobrien bfd_vma val; 183789857Sobrien bfd_size_type amt; 183860484Sobrien 183960484Sobrien globals = coff_arm_hash_table (info); 184060484Sobrien 184160484Sobrien BFD_ASSERT (globals != NULL); 184260484Sobrien BFD_ASSERT (globals->bfd_of_glue_owner != NULL); 184360484Sobrien 184460484Sobrien s = bfd_get_section_by_name 184560484Sobrien (globals->bfd_of_glue_owner, ARM2THUMB_GLUE_SECTION_NAME); 184660484Sobrien 184760484Sobrien BFD_ASSERT (s != NULL); 184860484Sobrien 184989857Sobrien amt = strlen (name) + strlen (ARM2THUMB_GLUE_ENTRY_NAME) + 1; 1850218822Sdim tmp_name = bfd_malloc (amt); 185160484Sobrien 185260484Sobrien BFD_ASSERT (tmp_name); 185360484Sobrien 185460484Sobrien sprintf (tmp_name, ARM2THUMB_GLUE_ENTRY_NAME, name); 185577298Sobrien 185660484Sobrien myh = coff_link_hash_lookup 1857130561Sobrien (coff_hash_table (info), tmp_name, FALSE, FALSE, TRUE); 185877298Sobrien 185960484Sobrien if (myh != NULL) 186060484Sobrien { 186160484Sobrien free (tmp_name); 1862218822Sdim /* We've already seen this guy. */ 1863218822Sdim return; 186460484Sobrien } 186560484Sobrien 186660484Sobrien /* The only trick here is using globals->arm_glue_size as the value. Even 186760484Sobrien though the section isn't allocated yet, this is where we will be putting 186860484Sobrien it. */ 1869107492Sobrien bh = NULL; 187089857Sobrien val = globals->arm_glue_size + 1; 187160484Sobrien bfd_coff_link_add_one_symbol (info, globals->bfd_of_glue_owner, tmp_name, 1872130561Sobrien BSF_GLOBAL, s, val, NULL, TRUE, FALSE, &bh); 187377298Sobrien 187460484Sobrien free (tmp_name); 187577298Sobrien 187660484Sobrien globals->arm_glue_size += ARM2THUMB_GLUE_SIZE; 187760484Sobrien 187860484Sobrien return; 187960484Sobrien} 188060484Sobrien 188199461Sobrien#ifndef ARM_WINCE 188260484Sobrienstatic void 1883218822Sdimrecord_thumb_to_arm_glue (struct bfd_link_info * info, 1884218822Sdim struct coff_link_hash_entry * h) 188560484Sobrien{ 188660484Sobrien const char * name = h->root.root.string; 1887218822Sdim asection * s; 188860484Sobrien char * tmp_name; 188960484Sobrien struct coff_link_hash_entry * myh; 1890107492Sobrien struct bfd_link_hash_entry * bh; 189160484Sobrien struct coff_arm_link_hash_table * globals; 189289857Sobrien bfd_vma val; 189389857Sobrien bfd_size_type amt; 189460484Sobrien 189560484Sobrien globals = coff_arm_hash_table (info); 189677298Sobrien 189760484Sobrien BFD_ASSERT (globals != NULL); 189860484Sobrien BFD_ASSERT (globals->bfd_of_glue_owner != NULL); 189960484Sobrien 190060484Sobrien s = bfd_get_section_by_name 190160484Sobrien (globals->bfd_of_glue_owner, THUMB2ARM_GLUE_SECTION_NAME); 190260484Sobrien 190360484Sobrien BFD_ASSERT (s != NULL); 190460484Sobrien 190589857Sobrien amt = strlen (name) + strlen (THUMB2ARM_GLUE_ENTRY_NAME) + 1; 1906218822Sdim tmp_name = bfd_malloc (amt); 190760484Sobrien 190860484Sobrien BFD_ASSERT (tmp_name); 190960484Sobrien 191060484Sobrien sprintf (tmp_name, THUMB2ARM_GLUE_ENTRY_NAME, name); 191160484Sobrien 191260484Sobrien myh = coff_link_hash_lookup 1913130561Sobrien (coff_hash_table (info), tmp_name, FALSE, FALSE, TRUE); 191477298Sobrien 191560484Sobrien if (myh != NULL) 191660484Sobrien { 191760484Sobrien free (tmp_name); 1918218822Sdim /* We've already seen this guy. */ 1919218822Sdim return; 192060484Sobrien } 192160484Sobrien 1922107492Sobrien bh = NULL; 192389857Sobrien val = globals->thumb_glue_size + 1; 192460484Sobrien bfd_coff_link_add_one_symbol (info, globals->bfd_of_glue_owner, tmp_name, 1925130561Sobrien BSF_GLOBAL, s, val, NULL, TRUE, FALSE, &bh); 192677298Sobrien 192760484Sobrien /* If we mark it 'thumb', the disassembler will do a better job. */ 1928107492Sobrien myh = (struct coff_link_hash_entry *) bh; 192960484Sobrien myh->class = C_THUMBEXTFUNC; 193060484Sobrien 193160484Sobrien free (tmp_name); 193260484Sobrien 193360484Sobrien /* Allocate another symbol to mark where we switch to arm mode. */ 193477298Sobrien 193560484Sobrien#define CHANGE_TO_ARM "__%s_change_to_arm" 193660484Sobrien#define BACK_FROM_ARM "__%s_back_from_arm" 193777298Sobrien 193889857Sobrien amt = strlen (name) + strlen (CHANGE_TO_ARM) + 1; 1939218822Sdim tmp_name = bfd_malloc (amt); 194077298Sobrien 194160484Sobrien BFD_ASSERT (tmp_name); 194277298Sobrien 194360484Sobrien sprintf (tmp_name, globals->support_old_code ? BACK_FROM_ARM : CHANGE_TO_ARM, name); 194460484Sobrien 1945107492Sobrien bh = NULL; 194689857Sobrien val = globals->thumb_glue_size + (globals->support_old_code ? 8 : 4); 194760484Sobrien bfd_coff_link_add_one_symbol (info, globals->bfd_of_glue_owner, tmp_name, 1948130561Sobrien BSF_LOCAL, s, val, NULL, TRUE, FALSE, &bh); 194960484Sobrien 195077298Sobrien free (tmp_name); 195177298Sobrien 195260484Sobrien globals->thumb_glue_size += THUMB2ARM_GLUE_SIZE; 195360484Sobrien 195460484Sobrien return; 195560484Sobrien} 195699461Sobrien#endif /* not ARM_WINCE */ 195760484Sobrien 195860484Sobrien/* Select a BFD to be used to hold the sections used by the glue code. 195960484Sobrien This function is called from the linker scripts in ld/emultempl/ 196060484Sobrien {armcoff/pe}.em */ 196160484Sobrien 1962130561Sobrienbfd_boolean 1963218822Sdimbfd_arm_get_bfd_for_interworking (bfd * abfd, 1964218822Sdim struct bfd_link_info * info) 196560484Sobrien{ 196660484Sobrien struct coff_arm_link_hash_table * globals; 196760484Sobrien flagword flags; 196860484Sobrien asection * sec; 196977298Sobrien 197060484Sobrien /* If we are only performing a partial link do not bother 197160484Sobrien getting a bfd to hold the glue. */ 1972130561Sobrien if (info->relocatable) 1973130561Sobrien return TRUE; 197477298Sobrien 197560484Sobrien globals = coff_arm_hash_table (info); 197677298Sobrien 197760484Sobrien BFD_ASSERT (globals != NULL); 197860484Sobrien 197960484Sobrien if (globals->bfd_of_glue_owner != NULL) 1980130561Sobrien return TRUE; 198177298Sobrien 198260484Sobrien sec = bfd_get_section_by_name (abfd, ARM2THUMB_GLUE_SECTION_NAME); 198377298Sobrien 198477298Sobrien if (sec == NULL) 198560484Sobrien { 1986218822Sdim flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY 1987218822Sdim | SEC_CODE | SEC_READONLY); 1988218822Sdim sec = bfd_make_section_with_flags (abfd, ARM2THUMB_GLUE_SECTION_NAME, 1989218822Sdim flags); 199060484Sobrien if (sec == NULL 199160484Sobrien || ! bfd_set_section_alignment (abfd, sec, 2)) 1992130561Sobrien return FALSE; 199360484Sobrien } 199460484Sobrien 199560484Sobrien sec = bfd_get_section_by_name (abfd, THUMB2ARM_GLUE_SECTION_NAME); 199660484Sobrien 199777298Sobrien if (sec == NULL) 199860484Sobrien { 1999218822Sdim flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY 2000218822Sdim | SEC_CODE | SEC_READONLY); 2001218822Sdim sec = bfd_make_section_with_flags (abfd, THUMB2ARM_GLUE_SECTION_NAME, 2002218822Sdim flags); 200377298Sobrien 200460484Sobrien if (sec == NULL 200560484Sobrien || ! bfd_set_section_alignment (abfd, sec, 2)) 2006130561Sobrien return FALSE; 200760484Sobrien } 200877298Sobrien 200960484Sobrien /* Save the bfd for later use. */ 201060484Sobrien globals->bfd_of_glue_owner = abfd; 201177298Sobrien 2012130561Sobrien return TRUE; 201360484Sobrien} 201460484Sobrien 2015130561Sobrienbfd_boolean 2016218822Sdimbfd_arm_process_before_allocation (bfd * abfd, 2017218822Sdim struct bfd_link_info * info, 2018218822Sdim int support_old_code) 201960484Sobrien{ 202060484Sobrien asection * sec; 202160484Sobrien struct coff_arm_link_hash_table * globals; 202260484Sobrien 202360484Sobrien /* If we are only performing a partial link do not bother 202460484Sobrien to construct any glue. */ 2025130561Sobrien if (info->relocatable) 2026130561Sobrien return TRUE; 202777298Sobrien 202860484Sobrien /* Here we have a bfd that is to be included on the link. We have a hook 202960484Sobrien to do reloc rummaging, before section sizes are nailed down. */ 203060484Sobrien _bfd_coff_get_external_symbols (abfd); 203160484Sobrien 203260484Sobrien globals = coff_arm_hash_table (info); 203377298Sobrien 203460484Sobrien BFD_ASSERT (globals != NULL); 203560484Sobrien BFD_ASSERT (globals->bfd_of_glue_owner != NULL); 203660484Sobrien 203760484Sobrien globals->support_old_code = support_old_code; 203877298Sobrien 203960484Sobrien /* Rummage around all the relocs and map the glue vectors. */ 204060484Sobrien sec = abfd->sections; 204160484Sobrien 204260484Sobrien if (sec == NULL) 2043130561Sobrien return TRUE; 204460484Sobrien 204560484Sobrien for (; sec != NULL; sec = sec->next) 204660484Sobrien { 204760484Sobrien struct internal_reloc * i; 204860484Sobrien struct internal_reloc * rel; 204960484Sobrien 205077298Sobrien if (sec->reloc_count == 0) 205160484Sobrien continue; 205260484Sobrien 205360484Sobrien /* Load the relocs. */ 205477298Sobrien /* FIXME: there may be a storage leak here. */ 205560484Sobrien i = _bfd_coff_read_internal_relocs (abfd, sec, 1, 0, 0, 0); 205677298Sobrien 205760484Sobrien BFD_ASSERT (i != 0); 205860484Sobrien 205977298Sobrien for (rel = i; rel < i + sec->reloc_count; ++rel) 206060484Sobrien { 206160484Sobrien unsigned short r_type = rel->r_type; 206260484Sobrien long symndx; 206360484Sobrien struct coff_link_hash_entry * h; 206460484Sobrien 206560484Sobrien symndx = rel->r_symndx; 206660484Sobrien 206777298Sobrien /* If the relocation is not against a symbol it cannot concern us. */ 206860484Sobrien if (symndx == -1) 206960484Sobrien continue; 207060484Sobrien 207160484Sobrien /* If the index is outside of the range of our table, something has gone wrong. */ 207260484Sobrien if (symndx >= obj_conv_table_size (abfd)) 207360484Sobrien { 2074218822Sdim _bfd_error_handler (_("%B: illegal symbol index in reloc: %d"), 2075218822Sdim abfd, symndx); 207660484Sobrien continue; 207760484Sobrien } 207877298Sobrien 207960484Sobrien h = obj_coff_sym_hashes (abfd)[symndx]; 208060484Sobrien 208160484Sobrien /* If the relocation is against a static symbol it must be within 208260484Sobrien the current section and so cannot be a cross ARM/Thumb relocation. */ 208360484Sobrien if (h == NULL) 208460484Sobrien continue; 208560484Sobrien 208660484Sobrien switch (r_type) 208760484Sobrien { 208860484Sobrien case ARM_26: 208960484Sobrien /* This one is a call from arm code. We need to look up 209060484Sobrien the target of the call. If it is a thumb target, we 209160484Sobrien insert glue. */ 209277298Sobrien 209360484Sobrien if (h->class == C_THUMBEXTFUNC) 209460484Sobrien record_arm_to_thumb_glue (info, h); 209560484Sobrien break; 209677298Sobrien 209760484Sobrien#ifndef ARM_WINCE 209860484Sobrien case ARM_THUMB23: 209960484Sobrien /* This one is a call from thumb code. We used to look 210060484Sobrien for ARM_THUMB9 and ARM_THUMB12 as well. We need to look 210160484Sobrien up the target of the call. If it is an arm target, we 210260484Sobrien insert glue. If the symbol does not exist it will be 210360484Sobrien given a class of C_EXT and so we will generate a stub 210460484Sobrien for it. This is not really a problem, since the link 210560484Sobrien is doomed anyway. */ 210660484Sobrien 210760484Sobrien switch (h->class) 210860484Sobrien { 210960484Sobrien case C_EXT: 211060484Sobrien case C_STAT: 211160484Sobrien case C_LABEL: 211260484Sobrien record_thumb_to_arm_glue (info, h); 211360484Sobrien break; 211460484Sobrien default: 211560484Sobrien ; 211660484Sobrien } 211760484Sobrien break; 211860484Sobrien#endif 211977298Sobrien 212060484Sobrien default: 212160484Sobrien break; 212260484Sobrien } 212360484Sobrien } 212460484Sobrien } 212560484Sobrien 2126130561Sobrien return TRUE; 212760484Sobrien} 212860484Sobrien 212960484Sobrien#endif /* ! defined (COFF_IMAGE_WITH_PE) */ 213060484Sobrien 213160484Sobrien#define coff_bfd_reloc_type_lookup coff_arm_reloc_type_lookup 2132218822Sdim#define coff_bfd_reloc_name_lookup coff_arm_reloc_name_lookup 213360484Sobrien#define coff_relocate_section coff_arm_relocate_section 213460484Sobrien#define coff_bfd_is_local_label_name coff_arm_is_local_label_name 213560484Sobrien#define coff_adjust_symndx coff_arm_adjust_symndx 213660484Sobrien#define coff_link_output_has_begun coff_arm_link_output_has_begun 213760484Sobrien#define coff_final_link_postscript coff_arm_final_link_postscript 213860484Sobrien#define coff_bfd_merge_private_bfd_data coff_arm_merge_private_bfd_data 213960484Sobrien#define coff_bfd_print_private_bfd_data coff_arm_print_private_bfd_data 214060484Sobrien#define coff_bfd_set_private_flags _bfd_coff_arm_set_private_flags 214160484Sobrien#define coff_bfd_copy_private_bfd_data coff_arm_copy_private_bfd_data 214260484Sobrien#define coff_bfd_link_hash_table_create coff_arm_link_hash_table_create 214360484Sobrien 2144130561Sobrien/* When doing a relocatable link, we want to convert ARM_26 relocs 2145130561Sobrien into ARM_26D relocs. */ 214660484Sobrien 2147130561Sobrienstatic bfd_boolean 2148218822Sdimcoff_arm_adjust_symndx (bfd *obfd ATTRIBUTE_UNUSED, 2149218822Sdim struct bfd_link_info *info ATTRIBUTE_UNUSED, 2150218822Sdim bfd *ibfd, 2151218822Sdim asection *sec, 2152218822Sdim struct internal_reloc *irel, 2153218822Sdim bfd_boolean *adjustedp) 215460484Sobrien{ 2155130561Sobrien if (irel->r_type == ARM_26) 215660484Sobrien { 215760484Sobrien struct coff_link_hash_entry *h; 215860484Sobrien 215960484Sobrien h = obj_coff_sym_hashes (ibfd)[irel->r_symndx]; 216060484Sobrien if (h != NULL 216160484Sobrien && (h->root.type == bfd_link_hash_defined 216260484Sobrien || h->root.type == bfd_link_hash_defweak) 216360484Sobrien && h->root.u.def.section->output_section == sec->output_section) 2164130561Sobrien irel->r_type = ARM_26D; 216560484Sobrien } 2166130561Sobrien *adjustedp = FALSE; 2167130561Sobrien return TRUE; 216860484Sobrien} 216960484Sobrien 217060484Sobrien/* Called when merging the private data areas of two BFDs. 217160484Sobrien This is important as it allows us to detect if we are 217260484Sobrien attempting to merge binaries compiled for different ARM 2173130561Sobrien targets, eg different CPUs or different APCS's. */ 217460484Sobrien 2175130561Sobrienstatic bfd_boolean 2176218822Sdimcoff_arm_merge_private_bfd_data (bfd * ibfd, bfd * obfd) 217760484Sobrien{ 217860484Sobrien BFD_ASSERT (ibfd != NULL && obfd != NULL); 217960484Sobrien 218060484Sobrien if (ibfd == obfd) 2181130561Sobrien return TRUE; 218260484Sobrien 218360484Sobrien /* If the two formats are different we cannot merge anything. 218460484Sobrien This is not an error, since it is permissable to change the 218560484Sobrien input and output formats. */ 218660484Sobrien if ( ibfd->xvec->flavour != bfd_target_coff_flavour 218760484Sobrien || obfd->xvec->flavour != bfd_target_coff_flavour) 2188130561Sobrien return TRUE; 218960484Sobrien 2190130561Sobrien /* Determine what should happen if the input ARM architecture 2191130561Sobrien does not match the output ARM architecture. */ 2192130561Sobrien if (! bfd_arm_merge_machines (ibfd, obfd)) 2193130561Sobrien return FALSE; 2194130561Sobrien 2195130561Sobrien /* Verify that the APCS is the same for the two BFDs. */ 219660484Sobrien if (APCS_SET (ibfd)) 219760484Sobrien { 219860484Sobrien if (APCS_SET (obfd)) 219960484Sobrien { 220060484Sobrien /* If the src and dest have different APCS flag bits set, fail. */ 220160484Sobrien if (APCS_26_FLAG (obfd) != APCS_26_FLAG (ibfd)) 220260484Sobrien { 220360484Sobrien _bfd_error_handler 220460484Sobrien /* xgettext: c-format */ 2205218822Sdim (_("ERROR: %B is compiled for APCS-%d, whereas %B is compiled for APCS-%d"), 2206218822Sdim ibfd, obfd, 2207218822Sdim APCS_26_FLAG (ibfd) ? 26 : 32, 2208218822Sdim APCS_26_FLAG (obfd) ? 26 : 32 220960484Sobrien ); 221060484Sobrien 221160484Sobrien bfd_set_error (bfd_error_wrong_format); 2212130561Sobrien return FALSE; 221360484Sobrien } 221477298Sobrien 221560484Sobrien if (APCS_FLOAT_FLAG (obfd) != APCS_FLOAT_FLAG (ibfd)) 221660484Sobrien { 221760484Sobrien const char *msg; 221860484Sobrien 221960484Sobrien if (APCS_FLOAT_FLAG (ibfd)) 222060484Sobrien /* xgettext: c-format */ 2221218822Sdim msg = _("ERROR: %B passes floats in float registers, whereas %B passes them in integer registers"); 222260484Sobrien else 222360484Sobrien /* xgettext: c-format */ 2224218822Sdim msg = _("ERROR: %B passes floats in integer registers, whereas %B passes them in float registers"); 222577298Sobrien 2226218822Sdim _bfd_error_handler (msg, ibfd, obfd); 222760484Sobrien 222860484Sobrien bfd_set_error (bfd_error_wrong_format); 2229130561Sobrien return FALSE; 223060484Sobrien } 223177298Sobrien 223260484Sobrien if (PIC_FLAG (obfd) != PIC_FLAG (ibfd)) 223360484Sobrien { 223460484Sobrien const char * msg; 223560484Sobrien 223660484Sobrien if (PIC_FLAG (ibfd)) 223760484Sobrien /* xgettext: c-format */ 2238218822Sdim msg = _("ERROR: %B is compiled as position independent code, whereas target %B is absolute position"); 223960484Sobrien else 224060484Sobrien /* xgettext: c-format */ 2241218822Sdim msg = _("ERROR: %B is compiled as absolute position code, whereas target %B is position independent"); 2242218822Sdim _bfd_error_handler (msg, ibfd, obfd); 224360484Sobrien 224460484Sobrien bfd_set_error (bfd_error_wrong_format); 2245130561Sobrien return FALSE; 224660484Sobrien } 224760484Sobrien } 224860484Sobrien else 224960484Sobrien { 225060484Sobrien SET_APCS_FLAGS (obfd, APCS_26_FLAG (ibfd) | APCS_FLOAT_FLAG (ibfd) | PIC_FLAG (ibfd)); 225177298Sobrien 225260484Sobrien /* Set up the arch and fields as well as these are probably wrong. */ 225360484Sobrien bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), bfd_get_mach (ibfd)); 225460484Sobrien } 225560484Sobrien } 225660484Sobrien 225760484Sobrien /* Check the interworking support. */ 225860484Sobrien if (INTERWORK_SET (ibfd)) 225960484Sobrien { 226060484Sobrien if (INTERWORK_SET (obfd)) 226160484Sobrien { 226260484Sobrien /* If the src and dest differ in their interworking issue a warning. */ 226360484Sobrien if (INTERWORK_FLAG (obfd) != INTERWORK_FLAG (ibfd)) 226460484Sobrien { 226560484Sobrien const char * msg; 226660484Sobrien 226760484Sobrien if (INTERWORK_FLAG (ibfd)) 226860484Sobrien /* xgettext: c-format */ 2269218822Sdim msg = _("Warning: %B supports interworking, whereas %B does not"); 227060484Sobrien else 227160484Sobrien /* xgettext: c-format */ 2272218822Sdim msg = _("Warning: %B does not support interworking, whereas %B does"); 227377298Sobrien 2274218822Sdim _bfd_error_handler (msg, ibfd, obfd); 227560484Sobrien } 227660484Sobrien } 227760484Sobrien else 227860484Sobrien { 227960484Sobrien SET_INTERWORK_FLAG (obfd, INTERWORK_FLAG (ibfd)); 228060484Sobrien } 228160484Sobrien } 228260484Sobrien 2283130561Sobrien return TRUE; 228460484Sobrien} 228560484Sobrien 228660484Sobrien/* Display the flags field. */ 228760484Sobrien 2288130561Sobrienstatic bfd_boolean 2289218822Sdimcoff_arm_print_private_bfd_data (bfd * abfd, void * ptr) 229060484Sobrien{ 229160484Sobrien FILE * file = (FILE *) ptr; 229277298Sobrien 229360484Sobrien BFD_ASSERT (abfd != NULL && ptr != NULL); 229477298Sobrien 229560484Sobrien /* xgettext:c-format */ 229660484Sobrien fprintf (file, _("private flags = %x:"), coff_data (abfd)->flags); 229777298Sobrien 229860484Sobrien if (APCS_SET (abfd)) 229960484Sobrien { 2300130561Sobrien /* xgettext: APCS is ARM Procedure Call Standard, it should not be translated. */ 230160484Sobrien fprintf (file, " [APCS-%d]", APCS_26_FLAG (abfd) ? 26 : 32); 230260484Sobrien 230360484Sobrien if (APCS_FLOAT_FLAG (abfd)) 230460484Sobrien fprintf (file, _(" [floats passed in float registers]")); 230560484Sobrien else 230660484Sobrien fprintf (file, _(" [floats passed in integer registers]")); 230760484Sobrien 230860484Sobrien if (PIC_FLAG (abfd)) 230960484Sobrien fprintf (file, _(" [position independent]")); 231060484Sobrien else 231160484Sobrien fprintf (file, _(" [absolute position]")); 231260484Sobrien } 231377298Sobrien 231460484Sobrien if (! INTERWORK_SET (abfd)) 231560484Sobrien fprintf (file, _(" [interworking flag not initialised]")); 231660484Sobrien else if (INTERWORK_FLAG (abfd)) 231760484Sobrien fprintf (file, _(" [interworking supported]")); 231860484Sobrien else 231960484Sobrien fprintf (file, _(" [interworking not supported]")); 232077298Sobrien 232160484Sobrien fputc ('\n', file); 232277298Sobrien 2323130561Sobrien return TRUE; 232460484Sobrien} 232560484Sobrien 232660484Sobrien/* Copies the given flags into the coff_tdata.flags field. 232760484Sobrien Typically these flags come from the f_flags[] field of 232860484Sobrien the COFF filehdr structure, which contains important, 232960484Sobrien target specific information. 233060484Sobrien Note: Although this function is static, it is explicitly 233160484Sobrien called from both coffcode.h and peicode.h. */ 233260484Sobrien 2333130561Sobrienstatic bfd_boolean 2334218822Sdim_bfd_coff_arm_set_private_flags (bfd * abfd, flagword flags) 233560484Sobrien{ 233660484Sobrien flagword flag; 233760484Sobrien 233860484Sobrien BFD_ASSERT (abfd != NULL); 233960484Sobrien 234060484Sobrien flag = (flags & F_APCS26) ? F_APCS_26 : 0; 234177298Sobrien 234260484Sobrien /* Make sure that the APCS field has not been initialised to the opposite 234360484Sobrien value. */ 234460484Sobrien if (APCS_SET (abfd) 234560484Sobrien && ( (APCS_26_FLAG (abfd) != flag) 234660484Sobrien || (APCS_FLOAT_FLAG (abfd) != (flags & F_APCS_FLOAT)) 234760484Sobrien || (PIC_FLAG (abfd) != (flags & F_PIC)) 234860484Sobrien )) 2349130561Sobrien return FALSE; 235060484Sobrien 235160484Sobrien flag |= (flags & (F_APCS_FLOAT | F_PIC)); 235277298Sobrien 235360484Sobrien SET_APCS_FLAGS (abfd, flag); 235460484Sobrien 235560484Sobrien flag = (flags & F_INTERWORK); 235677298Sobrien 235760484Sobrien /* If the BFD has already had its interworking flag set, but it 235860484Sobrien is different from the value that we have been asked to set, 235960484Sobrien then assume that that merged code will not support interworking 236060484Sobrien and set the flag accordingly. */ 236160484Sobrien if (INTERWORK_SET (abfd) && (INTERWORK_FLAG (abfd) != flag)) 236260484Sobrien { 236360484Sobrien if (flag) 236460484Sobrien /* xgettext: c-format */ 2365218822Sdim _bfd_error_handler (_("Warning: Not setting interworking flag of %B since it has already been specified as non-interworking"), 2366218822Sdim abfd); 236760484Sobrien else 236860484Sobrien /* xgettext: c-format */ 2369218822Sdim _bfd_error_handler (_("Warning: Clearing the interworking flag of %B due to outside request"), 2370218822Sdim abfd); 237160484Sobrien flag = 0; 237260484Sobrien } 237360484Sobrien 237460484Sobrien SET_INTERWORK_FLAG (abfd, flag); 237560484Sobrien 2376130561Sobrien return TRUE; 237760484Sobrien} 237860484Sobrien 237960484Sobrien/* Copy the important parts of the target specific data 238060484Sobrien from one instance of a BFD to another. */ 238160484Sobrien 2382130561Sobrienstatic bfd_boolean 2383218822Sdimcoff_arm_copy_private_bfd_data (bfd * src, bfd * dest) 238460484Sobrien{ 238560484Sobrien BFD_ASSERT (src != NULL && dest != NULL); 238677298Sobrien 238760484Sobrien if (src == dest) 2388130561Sobrien return TRUE; 238960484Sobrien 239060484Sobrien /* If the destination is not in the same format as the source, do not do 239160484Sobrien the copy. */ 239260484Sobrien if (src->xvec != dest->xvec) 2393130561Sobrien return TRUE; 239460484Sobrien 2395218822Sdim /* Copy the flags field. */ 239660484Sobrien if (APCS_SET (src)) 239760484Sobrien { 239860484Sobrien if (APCS_SET (dest)) 239960484Sobrien { 240060484Sobrien /* If the src and dest have different APCS flag bits set, fail. */ 240160484Sobrien if (APCS_26_FLAG (dest) != APCS_26_FLAG (src)) 2402130561Sobrien return FALSE; 240377298Sobrien 240460484Sobrien if (APCS_FLOAT_FLAG (dest) != APCS_FLOAT_FLAG (src)) 2405130561Sobrien return FALSE; 240677298Sobrien 240760484Sobrien if (PIC_FLAG (dest) != PIC_FLAG (src)) 2408130561Sobrien return FALSE; 240960484Sobrien } 241060484Sobrien else 241160484Sobrien SET_APCS_FLAGS (dest, APCS_26_FLAG (src) | APCS_FLOAT_FLAG (src) 241260484Sobrien | PIC_FLAG (src)); 241360484Sobrien } 241460484Sobrien 241560484Sobrien if (INTERWORK_SET (src)) 241660484Sobrien { 241760484Sobrien if (INTERWORK_SET (dest)) 241860484Sobrien { 241960484Sobrien /* If the src and dest have different interworking flags then turn 242060484Sobrien off the interworking bit. */ 242160484Sobrien if (INTERWORK_FLAG (dest) != INTERWORK_FLAG (src)) 242260484Sobrien { 242360484Sobrien if (INTERWORK_FLAG (dest)) 242460484Sobrien { 242560484Sobrien /* xgettext:c-format */ 242691041Sobrien _bfd_error_handler (("\ 2427218822SdimWarning: Clearing the interworking flag of %B because non-interworking code in %B has been linked with it"), 2428218822Sdim dest, src); 242960484Sobrien } 243077298Sobrien 243160484Sobrien SET_INTERWORK_FLAG (dest, 0); 243260484Sobrien } 243360484Sobrien } 243460484Sobrien else 243560484Sobrien { 243660484Sobrien SET_INTERWORK_FLAG (dest, INTERWORK_FLAG (src)); 243760484Sobrien } 243860484Sobrien } 243960484Sobrien 2440130561Sobrien return TRUE; 244160484Sobrien} 244260484Sobrien 244360484Sobrien/* Note: the definitions here of LOCAL_LABEL_PREFIX and USER_LABEL_PREIFX 244477298Sobrien *must* match the definitions in gcc/config/arm/{coff|semi|aout}.h. */ 2445218822Sdim#ifndef LOCAL_LABEL_PREFIX 244677298Sobrien#define LOCAL_LABEL_PREFIX "" 2447218822Sdim#endif 244860484Sobrien#ifndef USER_LABEL_PREFIX 244960484Sobrien#define USER_LABEL_PREFIX "_" 245060484Sobrien#endif 245160484Sobrien 245260484Sobrien/* Like _bfd_coff_is_local_label_name, but 245360484Sobrien a) test against USER_LABEL_PREFIX, to avoid stripping labels known to be 245460484Sobrien non-local. 245560484Sobrien b) Allow other prefixes than ".", e.g. an empty prefix would cause all 245660484Sobrien labels of the form Lxxx to be stripped. */ 2457218822Sdim 2458130561Sobrienstatic bfd_boolean 2459218822Sdimcoff_arm_is_local_label_name (bfd * abfd ATTRIBUTE_UNUSED, 2460218822Sdim const char * name) 246160484Sobrien{ 246260484Sobrien#ifdef USER_LABEL_PREFIX 246360484Sobrien if (USER_LABEL_PREFIX[0] != 0) 246460484Sobrien { 2465218822Sdim size_t len = strlen (USER_LABEL_PREFIX); 2466218822Sdim 2467218822Sdim if (strncmp (name, USER_LABEL_PREFIX, len) == 0) 2468130561Sobrien return FALSE; 246960484Sobrien } 247060484Sobrien#endif 247160484Sobrien 247260484Sobrien#ifdef LOCAL_LABEL_PREFIX 247360484Sobrien /* If there is a prefix for local labels then look for this. 247477298Sobrien If the prefix exists, but it is empty, then ignore the test. */ 247577298Sobrien 247660484Sobrien if (LOCAL_LABEL_PREFIX[0] != 0) 247760484Sobrien { 247889857Sobrien size_t len = strlen (LOCAL_LABEL_PREFIX); 247977298Sobrien 248060484Sobrien if (strncmp (name, LOCAL_LABEL_PREFIX, len) != 0) 2481130561Sobrien return FALSE; 248277298Sobrien 248360484Sobrien /* Perform the checks below for the rest of the name. */ 248460484Sobrien name += len; 248560484Sobrien } 248660484Sobrien#endif 248777298Sobrien 248860484Sobrien return name[0] == 'L'; 248960484Sobrien} 249060484Sobrien 249160484Sobrien/* This piece of machinery exists only to guarantee that the bfd that holds 249277298Sobrien the glue section is written last. 249360484Sobrien 249460484Sobrien This does depend on bfd_make_section attaching a new section to the 2495218822Sdim end of the section list for the bfd. */ 249660484Sobrien 2497130561Sobrienstatic bfd_boolean 2498218822Sdimcoff_arm_link_output_has_begun (bfd * sub, struct coff_final_link_info * info) 249960484Sobrien{ 250060484Sobrien return (sub->output_has_begun 250160484Sobrien || sub == coff_arm_hash_table (info->info)->bfd_of_glue_owner); 250260484Sobrien} 250360484Sobrien 2504130561Sobrienstatic bfd_boolean 2505218822Sdimcoff_arm_final_link_postscript (bfd * abfd ATTRIBUTE_UNUSED, 2506218822Sdim struct coff_final_link_info * pfinfo) 250760484Sobrien{ 250860484Sobrien struct coff_arm_link_hash_table * globals; 250960484Sobrien 251060484Sobrien globals = coff_arm_hash_table (pfinfo->info); 251177298Sobrien 251260484Sobrien BFD_ASSERT (globals != NULL); 251377298Sobrien 251460484Sobrien if (globals->bfd_of_glue_owner != NULL) 251560484Sobrien { 251660484Sobrien if (! _bfd_coff_link_input_bfd (pfinfo, globals->bfd_of_glue_owner)) 2517130561Sobrien return FALSE; 251877298Sobrien 2519130561Sobrien globals->bfd_of_glue_owner->output_has_begun = TRUE; 252060484Sobrien } 252177298Sobrien 2522130561Sobrien return bfd_arm_update_notes (abfd, ARM_NOTE_SECTION); 252360484Sobrien} 252460484Sobrien 252560484Sobrien#include "coffcode.h" 252660484Sobrien 252760484Sobrien#ifndef TARGET_LITTLE_SYM 252860484Sobrien#define TARGET_LITTLE_SYM armcoff_little_vec 252960484Sobrien#endif 253060484Sobrien#ifndef TARGET_LITTLE_NAME 253160484Sobrien#define TARGET_LITTLE_NAME "coff-arm-little" 253260484Sobrien#endif 253360484Sobrien#ifndef TARGET_BIG_SYM 253460484Sobrien#define TARGET_BIG_SYM armcoff_big_vec 253560484Sobrien#endif 253660484Sobrien#ifndef TARGET_BIG_NAME 253760484Sobrien#define TARGET_BIG_NAME "coff-arm-big" 253860484Sobrien#endif 253960484Sobrien 254060484Sobrien#ifndef TARGET_UNDERSCORE 254160484Sobrien#define TARGET_UNDERSCORE 0 254260484Sobrien#endif 254360484Sobrien 254477298Sobrien#ifndef EXTRA_S_FLAGS 254560484Sobrien#ifdef COFF_WITH_PE 2546130561Sobrien#define EXTRA_S_FLAGS (SEC_CODE | SEC_LINK_ONCE | SEC_LINK_DUPLICATES) 254760484Sobrien#else 2548130561Sobrien#define EXTRA_S_FLAGS SEC_CODE 254960484Sobrien#endif 255077298Sobrien#endif 255160484Sobrien 255260484Sobrien/* Forward declaration for use initialising alternative_target field. */ 255360484Sobrienextern const bfd_target TARGET_BIG_SYM ; 255460484Sobrien 255560484Sobrien/* Target vectors. */ 2556130561SobrienCREATE_LITTLE_COFF_TARGET_VEC (TARGET_LITTLE_SYM, TARGET_LITTLE_NAME, D_PAGED, EXTRA_S_FLAGS, TARGET_UNDERSCORE, & TARGET_BIG_SYM, COFF_SWAP_TABLE) 2557130561SobrienCREATE_BIG_COFF_TARGET_VEC (TARGET_BIG_SYM, TARGET_BIG_NAME, D_PAGED, EXTRA_S_FLAGS, TARGET_UNDERSCORE, & TARGET_LITTLE_SYM, COFF_SWAP_TABLE) 2558