1214571Sdim/* 32-bit ELF support for S+core. 2214571Sdim Copyright 2006, 2007 Free Software Foundation, Inc. 3214571Sdim Contributed by 4214571Sdim Mei Ligang (ligang@sunnorth.com.cn) 5214571Sdim Pei-Lin Tsai (pltsai@sunplus.com) 6214571Sdim 7214571Sdim This file is part of BFD, the Binary File Descriptor library. 8214571Sdim 9214571Sdim This program is free software; you can redistribute it and/or modify 10214571Sdim it under the terms of the GNU General Public License as published by 11214571Sdim the Free Software Foundation; either version 2 of the License, or 12214571Sdim (at your option) any later version. 13214571Sdim 14214571Sdim This program is distributed in the hope that it will be useful, 15214571Sdim but WITHOUT ANY WARRANTY; without even the implied warranty of 16214571Sdim MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17214571Sdim GNU General Public License for more details. 18214571Sdim 19214571Sdim You should have received a copy of the GNU General Public License 20214571Sdim along with this program; if not, write to the Free Software 21214571Sdim Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 22214571Sdim 23214571Sdim#include "sysdep.h" 24214571Sdim#include "bfd.h" 25214571Sdim#include "libbfd.h" 26214571Sdim#include "libiberty.h" 27214571Sdim#include "elf-bfd.h" 28214571Sdim#include "elf/score.h" 29214571Sdim#include "elf/common.h" 30214571Sdim#include "elf/internal.h" 31214571Sdim#include "hashtab.h" 32214571Sdim 33214571Sdim 34214571Sdim/* Score ELF linker hash table. */ 35214571Sdim 36214571Sdimstruct score_elf_link_hash_table 37214571Sdim{ 38214571Sdim /* The main hash table. */ 39214571Sdim struct elf_link_hash_table root; 40214571Sdim}; 41214571Sdim 42214571Sdim/* The SCORE ELF linker needs additional information for each symbol in 43214571Sdim the global hash table. */ 44214571Sdim 45214571Sdimstruct score_elf_link_hash_entry 46214571Sdim{ 47214571Sdim struct elf_link_hash_entry root; 48214571Sdim 49214571Sdim /* Number of R_SCORE_ABS32, R_SCORE_REL32 relocs against this symbol. */ 50214571Sdim unsigned int possibly_dynamic_relocs; 51214571Sdim 52214571Sdim /* If the R_SCORE_ABS32, R_SCORE_REL32 reloc is against a readonly section. */ 53214571Sdim bfd_boolean readonly_reloc; 54214571Sdim 55214571Sdim /* We must not create a stub for a symbol that has relocations related to 56214571Sdim taking the function's address, i.e. any but R_SCORE_CALL15 ones. */ 57214571Sdim bfd_boolean no_fn_stub; 58214571Sdim 59214571Sdim /* Are we forced local? This will only be set if we have converted 60214571Sdim the initial global GOT entry to a local GOT entry. */ 61214571Sdim bfd_boolean forced_local; 62214571Sdim}; 63214571Sdim 64214571Sdim/* Traverse a score ELF linker hash table. */ 65214571Sdim#define score_elf_link_hash_traverse(table, func, info) \ 66214571Sdim (elf_link_hash_traverse \ 67214571Sdim (&(table)->root, \ 68214571Sdim (bfd_boolean (*) (struct elf_link_hash_entry *, void *)) (func), \ 69214571Sdim (info))) 70214571Sdim 71214571Sdim/* Get the SCORE elf linker hash table from a link_info structure. */ 72214571Sdim#define score_elf_hash_table(info) \ 73214571Sdim ((struct score_elf_link_hash_table *) ((info)->hash)) 74214571Sdim 75214571Sdim/* This structure is used to hold .got entries while estimating got sizes. */ 76214571Sdimstruct score_got_entry 77214571Sdim{ 78214571Sdim /* The input bfd in which the symbol is defined. */ 79214571Sdim bfd *abfd; 80214571Sdim /* The index of the symbol, as stored in the relocation r_info, if 81214571Sdim we have a local symbol; -1 otherwise. */ 82214571Sdim long symndx; 83214571Sdim union 84214571Sdim { 85214571Sdim /* If abfd == NULL, an address that must be stored in the got. */ 86214571Sdim bfd_vma address; 87214571Sdim /* If abfd != NULL && symndx != -1, the addend of the relocation 88214571Sdim that should be added to the symbol value. */ 89214571Sdim bfd_vma addend; 90214571Sdim /* If abfd != NULL && symndx == -1, the hash table entry 91214571Sdim corresponding to a global symbol in the got (or, local, if 92214571Sdim h->forced_local). */ 93214571Sdim struct score_elf_link_hash_entry *h; 94214571Sdim } d; 95214571Sdim 96214571Sdim /* The offset from the beginning of the .got section to the entry 97214571Sdim corresponding to this symbol+addend. If it's a global symbol 98214571Sdim whose offset is yet to be decided, it's going to be -1. */ 99214571Sdim long gotidx; 100214571Sdim}; 101214571Sdim 102214571Sdim/* This structure is passed to score_elf_sort_hash_table_f when sorting 103214571Sdim the dynamic symbols. */ 104214571Sdim 105214571Sdimstruct score_elf_hash_sort_data 106214571Sdim{ 107214571Sdim /* The symbol in the global GOT with the lowest dynamic symbol table index. */ 108214571Sdim struct elf_link_hash_entry *low; 109214571Sdim /* The least dynamic symbol table index corresponding to a symbol with a GOT entry. */ 110214571Sdim long min_got_dynindx; 111214571Sdim /* The greatest dynamic symbol table index corresponding to a symbol 112214571Sdim with a GOT entry that is not referenced (e.g., a dynamic symbol 113214571Sdim with dynamic relocations pointing to it from non-primary GOTs). */ 114214571Sdim long max_unref_got_dynindx; 115214571Sdim /* The greatest dynamic symbol table index not corresponding to a 116214571Sdim symbol without a GOT entry. */ 117214571Sdim long max_non_got_dynindx; 118214571Sdim}; 119214571Sdim 120214571Sdimstruct score_got_info 121214571Sdim{ 122214571Sdim /* The global symbol in the GOT with the lowest index in the dynamic 123214571Sdim symbol table. */ 124214571Sdim struct elf_link_hash_entry *global_gotsym; 125214571Sdim /* The number of global .got entries. */ 126214571Sdim unsigned int global_gotno; 127214571Sdim /* The number of local .got entries. */ 128214571Sdim unsigned int local_gotno; 129214571Sdim /* The number of local .got entries we have used. */ 130214571Sdim unsigned int assigned_gotno; 131214571Sdim /* A hash table holding members of the got. */ 132214571Sdim struct htab *got_entries; 133214571Sdim /* In multi-got links, a pointer to the next got (err, rather, most 134214571Sdim of the time, it points to the previous got). */ 135214571Sdim struct score_got_info *next; 136214571Sdim}; 137214571Sdim 138214571Sdim/* A structure used to count GOT entries, for GOT entry or ELF symbol table traversal. */ 139214571Sdimstruct _score_elf_section_data 140214571Sdim{ 141214571Sdim struct bfd_elf_section_data elf; 142214571Sdim union 143214571Sdim { 144214571Sdim struct score_got_info *got_info; 145214571Sdim bfd_byte *tdata; 146214571Sdim } 147214571Sdim u; 148214571Sdim}; 149214571Sdim 150214571Sdim#define score_elf_section_data(sec) \ 151214571Sdim ((struct _score_elf_section_data *) elf_section_data (sec)) 152214571Sdim 153214571Sdim/* The size of a symbol-table entry. */ 154214571Sdim#define SCORE_ELF_SYM_SIZE(abfd) \ 155214571Sdim (get_elf_backend_data (abfd)->s->sizeof_sym) 156214571Sdim 157214571Sdim/* In case we're on a 32-bit machine, construct a 64-bit "-1" value 158214571Sdim from smaller values. Start with zero, widen, *then* decrement. */ 159214571Sdim#define MINUS_ONE (((bfd_vma)0) - 1) 160214571Sdim#define MINUS_TWO (((bfd_vma)0) - 2) 161214571Sdim 162214571Sdim#define PDR_SIZE 32 163214571Sdim 164214571Sdim 165214571Sdim/* The number of local .got entries we reserve. */ 166214571Sdim#define SCORE_RESERVED_GOTNO (2) 167214571Sdim#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1" 168214571Sdim 169214571Sdim/* The offset of $gp from the beginning of the .got section. */ 170214571Sdim#define ELF_SCORE_GP_OFFSET(abfd) (0x3ff0) 171214571Sdim/* The maximum size of the GOT for it to be addressable using 15-bit offsets from $gp. */ 172214571Sdim#define SCORE_ELF_GOT_MAX_SIZE(abfd) (ELF_SCORE_GP_OFFSET(abfd) + 0x3fff) 173214571Sdim 174214571Sdim#define SCORE_ELF_STUB_SECTION_NAME (".SCORE.stub") 175214571Sdim#define SCORE_FUNCTION_STUB_SIZE (16) 176214571Sdim 177214571Sdim#define STUB_LW 0xc3bcc010 /* lw r29, [r28, -0x3ff0] */ 178214571Sdim#define STUB_MOVE 0x8363bc56 /* mv r27, r3 */ 179214571Sdim#define STUB_LI16 0x87548000 /* ori r26, .dynsym_index */ 180214571Sdim#define STUB_BRL 0x801dbc09 /* brl r29 */ 181214571Sdim 182214571Sdim#define SCORE_ELF_GOT_SIZE(abfd) \ 183214571Sdim (get_elf_backend_data (abfd)->s->arch_size / 8) 184214571Sdim 185214571Sdim#define SCORE_ELF_ADD_DYNAMIC_ENTRY(info, tag, val) \ 186214571Sdim (_bfd_elf_add_dynamic_entry (info, (bfd_vma) tag, (bfd_vma) val)) 187214571Sdim 188214571Sdim/* The size of an external dynamic table entry. */ 189214571Sdim#define SCORE_ELF_DYN_SIZE(abfd) \ 190214571Sdim (get_elf_backend_data (abfd)->s->sizeof_dyn) 191214571Sdim 192214571Sdim/* The size of an external REL relocation. */ 193214571Sdim#define SCORE_ELF_REL_SIZE(abfd) \ 194214571Sdim (get_elf_backend_data (abfd)->s->sizeof_rel) 195214571Sdim 196214571Sdim/* The default alignment for sections, as a power of two. */ 197214571Sdim#define SCORE_ELF_LOG_FILE_ALIGN(abfd)\ 198214571Sdim (get_elf_backend_data (abfd)->s->log_file_align) 199214571Sdim 200214571Sdim#ifndef NUM_ELEM 201214571Sdim#define NUM_ELEM(a) (sizeof (a) / (sizeof (a)[0])) 202214571Sdim#endif 203214571Sdim 204214571Sdimstatic bfd_byte *hi16_rel_addr; 205214571Sdim 206214571Sdim/* This will be used when we sort the dynamic relocation records. */ 207214571Sdimstatic bfd *reldyn_sorting_bfd; 208214571Sdim 209214571Sdim/* SCORE ELF uses two common sections. One is the usual one, and the 210214571Sdim other is for small objects. All the small objects are kept 211214571Sdim together, and then referenced via the gp pointer, which yields 212214571Sdim faster assembler code. This is what we use for the small common 213214571Sdim section. This approach is copied from ecoff.c. */ 214214571Sdimstatic asection score_elf_scom_section; 215214571Sdimstatic asymbol score_elf_scom_symbol; 216214571Sdimstatic asymbol *score_elf_scom_symbol_ptr; 217214571Sdim 218214571Sdimstatic bfd_reloc_status_type 219214571Sdimscore_elf_hi16_reloc (bfd *abfd ATTRIBUTE_UNUSED, 220214571Sdim arelent *reloc_entry, 221214571Sdim asymbol *symbol ATTRIBUTE_UNUSED, 222214571Sdim void * data, 223214571Sdim asection *input_section ATTRIBUTE_UNUSED, 224214571Sdim bfd *output_bfd ATTRIBUTE_UNUSED, 225214571Sdim char **error_message ATTRIBUTE_UNUSED) 226214571Sdim{ 227214571Sdim hi16_rel_addr = (bfd_byte *) data + reloc_entry->address; 228214571Sdim return bfd_reloc_ok; 229214571Sdim} 230214571Sdim 231214571Sdimstatic bfd_reloc_status_type 232214571Sdimscore_elf_lo16_reloc (bfd *abfd, 233214571Sdim arelent *reloc_entry, 234214571Sdim asymbol *symbol ATTRIBUTE_UNUSED, 235214571Sdim void * data, 236214571Sdim asection *input_section, 237214571Sdim bfd *output_bfd ATTRIBUTE_UNUSED, 238214571Sdim char **error_message ATTRIBUTE_UNUSED) 239214571Sdim{ 240214571Sdim bfd_vma addend = 0, offset = 0; 241214571Sdim unsigned long val; 242214571Sdim unsigned long hi16_offset, hi16_value, uvalue; 243214571Sdim 244214571Sdim hi16_value = bfd_get_32 (abfd, hi16_rel_addr); 245214571Sdim hi16_offset = ((((hi16_value >> 16) & 0x3) << 15) | (hi16_value & 0x7fff)) >> 1; 246214571Sdim addend = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); 247214571Sdim offset = ((((addend >> 16) & 0x3) << 15) | (addend & 0x7fff)) >> 1; 248214571Sdim val = reloc_entry->addend; 249214571Sdim if (reloc_entry->address > input_section->size) 250214571Sdim return bfd_reloc_outofrange; 251214571Sdim uvalue = ((hi16_offset << 16) | (offset & 0xffff)) + val; 252214571Sdim hi16_offset = (uvalue >> 16) << 1; 253214571Sdim hi16_value = (hi16_value & ~0x37fff) | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000); 254214571Sdim bfd_put_32 (abfd, hi16_value, hi16_rel_addr); 255214571Sdim offset = (uvalue & 0xffff) << 1; 256214571Sdim addend = (addend & ~0x37fff) | (offset & 0x7fff) | ((offset << 1) & 0x30000); 257214571Sdim bfd_put_32 (abfd, addend, (bfd_byte *) data + reloc_entry->address); 258214571Sdim return bfd_reloc_ok; 259214571Sdim} 260214571Sdim 261214571Sdim/* Set the GP value for OUTPUT_BFD. Returns FALSE if this is a 262214571Sdim dangerous relocation. */ 263214571Sdim 264214571Sdimstatic bfd_boolean 265214571Sdimscore_elf_assign_gp (bfd *output_bfd, bfd_vma *pgp) 266214571Sdim{ 267214571Sdim unsigned int count; 268214571Sdim asymbol **sym; 269214571Sdim unsigned int i; 270214571Sdim 271214571Sdim /* If we've already figured out what GP will be, just return it. */ 272214571Sdim *pgp = _bfd_get_gp_value (output_bfd); 273214571Sdim if (*pgp) 274214571Sdim return TRUE; 275214571Sdim 276214571Sdim count = bfd_get_symcount (output_bfd); 277214571Sdim sym = bfd_get_outsymbols (output_bfd); 278214571Sdim 279214571Sdim /* The linker script will have created a symbol named `_gp' with the 280214571Sdim appropriate value. */ 281214571Sdim if (sym == NULL) 282214571Sdim i = count; 283214571Sdim else 284214571Sdim { 285214571Sdim for (i = 0; i < count; i++, sym++) 286214571Sdim { 287214571Sdim const char *name; 288214571Sdim 289214571Sdim name = bfd_asymbol_name (*sym); 290214571Sdim if (*name == '_' && strcmp (name, "_gp") == 0) 291214571Sdim { 292214571Sdim *pgp = bfd_asymbol_value (*sym); 293214571Sdim _bfd_set_gp_value (output_bfd, *pgp); 294214571Sdim break; 295214571Sdim } 296214571Sdim } 297214571Sdim } 298214571Sdim 299214571Sdim if (i >= count) 300214571Sdim { 301214571Sdim /* Only get the error once. */ 302214571Sdim *pgp = 4; 303214571Sdim _bfd_set_gp_value (output_bfd, *pgp); 304214571Sdim return FALSE; 305214571Sdim } 306214571Sdim 307214571Sdim return TRUE; 308214571Sdim} 309214571Sdim 310214571Sdim/* We have to figure out the gp value, so that we can adjust the 311214571Sdim symbol value correctly. We look up the symbol _gp in the output 312214571Sdim BFD. If we can't find it, we're stuck. We cache it in the ELF 313214571Sdim target data. We don't need to adjust the symbol value for an 314214571Sdim external symbol if we are producing relocatable output. */ 315214571Sdim 316214571Sdimstatic bfd_reloc_status_type 317214571Sdimscore_elf_final_gp (bfd *output_bfd, 318214571Sdim asymbol *symbol, 319214571Sdim bfd_boolean relocatable, 320214571Sdim char **error_message, 321214571Sdim bfd_vma *pgp) 322214571Sdim{ 323214571Sdim if (bfd_is_und_section (symbol->section) 324214571Sdim && ! relocatable) 325214571Sdim { 326214571Sdim *pgp = 0; 327214571Sdim return bfd_reloc_undefined; 328214571Sdim } 329214571Sdim 330214571Sdim *pgp = _bfd_get_gp_value (output_bfd); 331214571Sdim if (*pgp == 0 332214571Sdim && (! relocatable 333214571Sdim || (symbol->flags & BSF_SECTION_SYM) != 0)) 334214571Sdim { 335214571Sdim if (relocatable) 336214571Sdim { 337214571Sdim /* Make up a value. */ 338214571Sdim *pgp = symbol->section->output_section->vma + 0x4000; 339214571Sdim _bfd_set_gp_value (output_bfd, *pgp); 340214571Sdim } 341214571Sdim else if (!score_elf_assign_gp (output_bfd, pgp)) 342214571Sdim { 343214571Sdim *error_message = 344214571Sdim (char *) _("GP relative relocation when _gp not defined"); 345214571Sdim return bfd_reloc_dangerous; 346214571Sdim } 347214571Sdim } 348214571Sdim 349214571Sdim return bfd_reloc_ok; 350214571Sdim} 351214571Sdim 352214571Sdimstatic bfd_reloc_status_type 353214571Sdimscore_elf_gprel15_with_gp (bfd *abfd, 354214571Sdim asymbol *symbol, 355214571Sdim arelent *reloc_entry, 356214571Sdim asection *input_section, 357214571Sdim bfd_boolean relocateable, 358214571Sdim void * data, 359214571Sdim bfd_vma gp ATTRIBUTE_UNUSED) 360214571Sdim{ 361214571Sdim bfd_vma relocation; 362214571Sdim unsigned long insn; 363214571Sdim 364214571Sdim if (bfd_is_com_section (symbol->section)) 365214571Sdim relocation = 0; 366214571Sdim else 367214571Sdim relocation = symbol->value; 368214571Sdim 369214571Sdim relocation += symbol->section->output_section->vma; 370214571Sdim relocation += symbol->section->output_offset; 371214571Sdim if (reloc_entry->address > input_section->size) 372214571Sdim return bfd_reloc_outofrange; 373214571Sdim 374214571Sdim insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); 375214571Sdim if (((reloc_entry->addend & 0xffffc000) != 0) 376214571Sdim && ((reloc_entry->addend & 0xffffc000) != 0xffffc000)) 377214571Sdim return bfd_reloc_overflow; 378214571Sdim 379214571Sdim insn = (insn & ~0x7fff) | (reloc_entry->addend & 0x7fff); 380214571Sdim bfd_put_32 (abfd, insn, (bfd_byte *) data + reloc_entry->address); 381214571Sdim if (relocateable) 382214571Sdim reloc_entry->address += input_section->output_offset; 383214571Sdim 384214571Sdim return bfd_reloc_ok; 385214571Sdim} 386214571Sdim 387214571Sdimstatic bfd_reloc_status_type 388214571Sdimgprel32_with_gp (bfd *abfd, asymbol *symbol, arelent *reloc_entry, 389214571Sdim asection *input_section, bfd_boolean relocatable, 390214571Sdim void *data, bfd_vma gp) 391214571Sdim{ 392214571Sdim bfd_vma relocation; 393214571Sdim bfd_vma val; 394214571Sdim 395214571Sdim if (bfd_is_com_section (symbol->section)) 396214571Sdim relocation = 0; 397214571Sdim else 398214571Sdim relocation = symbol->value; 399214571Sdim 400214571Sdim relocation += symbol->section->output_section->vma; 401214571Sdim relocation += symbol->section->output_offset; 402214571Sdim 403214571Sdim if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) 404214571Sdim return bfd_reloc_outofrange; 405214571Sdim 406214571Sdim /* Set val to the offset into the section or symbol. */ 407214571Sdim val = reloc_entry->addend; 408214571Sdim 409214571Sdim if (reloc_entry->howto->partial_inplace) 410214571Sdim val += bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); 411214571Sdim 412214571Sdim /* Adjust val for the final section location and GP value. If we 413214571Sdim are producing relocatable output, we don't want to do this for 414214571Sdim an external symbol. */ 415214571Sdim if (! relocatable 416214571Sdim || (symbol->flags & BSF_SECTION_SYM) != 0) 417214571Sdim val += relocation - gp; 418214571Sdim 419214571Sdim if (reloc_entry->howto->partial_inplace) 420214571Sdim bfd_put_32 (abfd, val, (bfd_byte *) data + reloc_entry->address); 421214571Sdim else 422214571Sdim reloc_entry->addend = val; 423214571Sdim 424214571Sdim if (relocatable) 425214571Sdim reloc_entry->address += input_section->output_offset; 426214571Sdim 427214571Sdim return bfd_reloc_ok; 428214571Sdim} 429214571Sdim 430214571Sdimstatic bfd_reloc_status_type 431214571Sdimscore_elf_gprel15_reloc (bfd *abfd, 432214571Sdim arelent *reloc_entry, 433214571Sdim asymbol *symbol, 434214571Sdim void * data, 435214571Sdim asection *input_section, 436214571Sdim bfd *output_bfd, 437214571Sdim char **error_message) 438214571Sdim{ 439214571Sdim bfd_boolean relocateable; 440214571Sdim bfd_reloc_status_type ret; 441214571Sdim bfd_vma gp; 442214571Sdim 443214571Sdim if (output_bfd != (bfd *) NULL 444214571Sdim && (symbol->flags & BSF_SECTION_SYM) == 0 && reloc_entry->addend == 0) 445214571Sdim { 446214571Sdim reloc_entry->address += input_section->output_offset; 447214571Sdim return bfd_reloc_ok; 448214571Sdim } 449214571Sdim if (output_bfd != (bfd *) NULL) 450214571Sdim relocateable = TRUE; 451214571Sdim else 452214571Sdim { 453214571Sdim relocateable = FALSE; 454214571Sdim output_bfd = symbol->section->output_section->owner; 455214571Sdim } 456214571Sdim 457214571Sdim ret = score_elf_final_gp (output_bfd, symbol, relocateable, error_message, &gp); 458214571Sdim if (ret != bfd_reloc_ok) 459214571Sdim return ret; 460214571Sdim 461214571Sdim return score_elf_gprel15_with_gp (abfd, symbol, reloc_entry, 462214571Sdim input_section, relocateable, data, gp); 463214571Sdim} 464214571Sdim 465214571Sdim/* Do a R_SCORE_GPREL32 relocation. This is a 32 bit value which must 466214571Sdim become the offset from the gp register. */ 467214571Sdim 468214571Sdimstatic bfd_reloc_status_type 469214571Sdimscore_elf_gprel32_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, 470214571Sdim void *data, asection *input_section, bfd *output_bfd, 471214571Sdim char **error_message) 472214571Sdim{ 473214571Sdim bfd_boolean relocatable; 474214571Sdim bfd_reloc_status_type ret; 475214571Sdim bfd_vma gp; 476214571Sdim 477214571Sdim /* R_SCORE_GPREL32 relocations are defined for local symbols only. */ 478214571Sdim if (output_bfd != NULL 479214571Sdim && (symbol->flags & BSF_SECTION_SYM) == 0 480214571Sdim && (symbol->flags & BSF_LOCAL) != 0) 481214571Sdim { 482214571Sdim *error_message = (char *) 483214571Sdim _("32bits gp relative relocation occurs for an external symbol"); 484214571Sdim return bfd_reloc_outofrange; 485214571Sdim } 486214571Sdim 487214571Sdim if (output_bfd != NULL) 488214571Sdim relocatable = TRUE; 489214571Sdim else 490214571Sdim { 491214571Sdim relocatable = FALSE; 492214571Sdim output_bfd = symbol->section->output_section->owner; 493214571Sdim } 494214571Sdim 495214571Sdim ret = score_elf_final_gp (output_bfd, symbol, relocatable, error_message, &gp); 496214571Sdim if (ret != bfd_reloc_ok) 497214571Sdim return ret; 498214571Sdim 499214571Sdim gp = 0; /* FIXME. */ 500214571Sdim return gprel32_with_gp (abfd, symbol, reloc_entry, input_section, 501214571Sdim relocatable, data, gp); 502214571Sdim} 503214571Sdim 504214571Sdim/* A howto special_function for R_SCORE_GOT15 relocations. This is just 505214571Sdim like any other 16-bit relocation when applied to global symbols, but is 506214571Sdim treated in the same as R_SCORE_HI16 when applied to local symbols. */ 507214571Sdim 508214571Sdimstatic bfd_reloc_status_type 509214571Sdimscore_elf_got15_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, 510214571Sdim void *data, asection *input_section, 511214571Sdim bfd *output_bfd, char **error_message) 512214571Sdim{ 513214571Sdim if ((symbol->flags & (BSF_GLOBAL | BSF_WEAK)) != 0 514214571Sdim || bfd_is_und_section (bfd_get_section (symbol)) 515214571Sdim || bfd_is_com_section (bfd_get_section (symbol))) 516214571Sdim /* The relocation is against a global symbol. */ 517214571Sdim return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, 518214571Sdim input_section, output_bfd, 519214571Sdim error_message); 520214571Sdim 521214571Sdim return score_elf_hi16_reloc (abfd, reloc_entry, symbol, data, 522214571Sdim input_section, output_bfd, error_message); 523214571Sdim} 524214571Sdim 525214571Sdimstatic bfd_reloc_status_type 526214571Sdimscore_elf_got_lo16_reloc (bfd *abfd, 527214571Sdim arelent *reloc_entry, 528214571Sdim asymbol *symbol ATTRIBUTE_UNUSED, 529214571Sdim void * data, 530214571Sdim asection *input_section, 531214571Sdim bfd *output_bfd ATTRIBUTE_UNUSED, 532214571Sdim char **error_message ATTRIBUTE_UNUSED) 533214571Sdim{ 534214571Sdim bfd_vma addend = 0, offset = 0; 535214571Sdim signed long val; 536214571Sdim signed long hi16_offset, hi16_value, uvalue; 537214571Sdim 538214571Sdim hi16_value = bfd_get_32 (abfd, hi16_rel_addr); 539214571Sdim hi16_offset = ((((hi16_value >> 16) & 0x3) << 15) | (hi16_value & 0x7fff)) >> 1; 540214571Sdim addend = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); 541214571Sdim offset = ((((addend >> 16) & 0x3) << 15) | (addend & 0x7fff)) >> 1; 542214571Sdim val = reloc_entry->addend; 543214571Sdim if (reloc_entry->address > input_section->size) 544214571Sdim return bfd_reloc_outofrange; 545214571Sdim uvalue = ((hi16_offset << 16) | (offset & 0xffff)) + val; 546214571Sdim if ((uvalue > -0x8000) && (uvalue < 0x7fff)) 547214571Sdim hi16_offset = 0; 548214571Sdim else 549214571Sdim hi16_offset = (uvalue >> 16) & 0x7fff; 550214571Sdim hi16_value = (hi16_value & ~0x37fff) | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000); 551214571Sdim bfd_put_32 (abfd, hi16_value, hi16_rel_addr); 552214571Sdim offset = (uvalue & 0xffff) << 1; 553214571Sdim addend = (addend & ~0x37fff) | (offset & 0x7fff) | ((offset << 1) & 0x30000); 554214571Sdim bfd_put_32 (abfd, addend, (bfd_byte *) data + reloc_entry->address); 555214571Sdim return bfd_reloc_ok; 556214571Sdim} 557214571Sdim 558214571Sdimstatic reloc_howto_type elf32_score_howto_table[] = 559214571Sdim{ 560214571Sdim /* No relocation. */ 561214571Sdim HOWTO (R_SCORE_NONE, /* type */ 562214571Sdim 0, /* rightshift */ 563214571Sdim 0, /* size (0 = byte, 1 = short, 2 = long) */ 564214571Sdim 0, /* bitsize */ 565214571Sdim FALSE, /* pc_relative */ 566214571Sdim 0, /* bitpos */ 567214571Sdim complain_overflow_dont,/* complain_on_overflow */ 568214571Sdim bfd_elf_generic_reloc, /* special_function */ 569214571Sdim "R_SCORE_NONE", /* name */ 570214571Sdim FALSE, /* partial_inplace */ 571214571Sdim 0, /* src_mask */ 572214571Sdim 0, /* dst_mask */ 573214571Sdim FALSE), /* pcrel_offset */ 574214571Sdim 575214571Sdim /* R_SCORE_HI16 */ 576214571Sdim HOWTO (R_SCORE_HI16, /* type */ 577214571Sdim 0, /* rightshift */ 578214571Sdim 2, /* size (0 = byte, 1 = short, 2 = long) */ 579214571Sdim 16, /* bitsize */ 580214571Sdim FALSE, /* pc_relative */ 581214571Sdim 1, /* bitpos */ 582214571Sdim complain_overflow_dont,/* complain_on_overflow */ 583214571Sdim score_elf_hi16_reloc, /* special_function */ 584214571Sdim "R_SCORE_HI16", /* name */ 585214571Sdim TRUE, /* partial_inplace */ 586214571Sdim 0x37fff, /* src_mask */ 587214571Sdim 0x37fff, /* dst_mask */ 588214571Sdim FALSE), /* pcrel_offset */ 589214571Sdim 590214571Sdim /* R_SCORE_LO16 */ 591214571Sdim HOWTO (R_SCORE_LO16, /* type */ 592214571Sdim 0, /* rightshift */ 593214571Sdim 2, /* size (0 = byte, 1 = short, 2 = long) */ 594214571Sdim 16, /* bitsize */ 595214571Sdim FALSE, /* pc_relative */ 596214571Sdim 1, /* bitpos */ 597214571Sdim complain_overflow_dont,/* complain_on_overflow */ 598214571Sdim score_elf_lo16_reloc, /* special_function */ 599214571Sdim "R_SCORE_LO16", /* name */ 600214571Sdim TRUE, /* partial_inplace */ 601214571Sdim 0x37fff, /* src_mask */ 602214571Sdim 0x37fff, /* dst_mask */ 603214571Sdim FALSE), /* pcrel_offset */ 604214571Sdim 605214571Sdim /* R_SCORE_DUMMY1 */ 606214571Sdim HOWTO (R_SCORE_DUMMY1, /* type */ 607214571Sdim 0, /* rightshift */ 608214571Sdim 2, /* size (0 = byte, 1 = short, 2 = long) */ 609214571Sdim 16, /* bitsize */ 610214571Sdim FALSE, /* pc_relative */ 611214571Sdim 1, /* bitpos */ 612214571Sdim complain_overflow_dont,/* complain_on_overflow */ 613214571Sdim bfd_elf_generic_reloc, /* special_function */ 614214571Sdim "R_SCORE_DUMMY1", /* name */ 615214571Sdim TRUE, /* partial_inplace */ 616214571Sdim 0x0000ffff, /* src_mask */ 617214571Sdim 0x0000ffff, /* dst_mask */ 618214571Sdim FALSE), /* pcrel_offset */ 619214571Sdim 620214571Sdim /*R_SCORE_24 */ 621214571Sdim HOWTO (R_SCORE_24, /* type */ 622214571Sdim 1, /* rightshift */ 623214571Sdim 2, /* size (0 = byte, 1 = short, 2 = long) */ 624214571Sdim 24, /* bitsize */ 625214571Sdim FALSE, /* pc_relative */ 626214571Sdim 1, /* bitpos */ 627214571Sdim complain_overflow_dont,/* complain_on_overflow */ 628214571Sdim bfd_elf_generic_reloc, /* special_function */ 629214571Sdim "R_SCORE_24", /* name */ 630214571Sdim FALSE, /* partial_inplace */ 631214571Sdim 0x3ff7fff, /* src_mask */ 632214571Sdim 0x3ff7fff, /* dst_mask */ 633214571Sdim FALSE), /* pcrel_offset */ 634214571Sdim 635214571Sdim /*R_SCORE_PC19 */ 636214571Sdim HOWTO (R_SCORE_PC19, /* type */ 637214571Sdim 1, /* rightshift */ 638214571Sdim 2, /* size (0 = byte, 1 = short, 2 = long) */ 639214571Sdim 19, /* bitsize */ 640214571Sdim TRUE, /* pc_relative */ 641214571Sdim 1, /* bitpos */ 642214571Sdim complain_overflow_dont,/* complain_on_overflow */ 643214571Sdim bfd_elf_generic_reloc, /* special_function */ 644214571Sdim "R_SCORE_PC19", /* name */ 645214571Sdim FALSE, /* partial_inplace */ 646214571Sdim 0x3ff03fe, /* src_mask */ 647214571Sdim 0x3ff03fe, /* dst_mask */ 648214571Sdim FALSE), /* pcrel_offset */ 649214571Sdim 650214571Sdim /*R_SCORE16_11 */ 651214571Sdim HOWTO (R_SCORE16_11, /* type */ 652214571Sdim 1, /* rightshift */ 653214571Sdim 1, /* size (0 = byte, 1 = short, 2 = long) */ 654214571Sdim 11, /* bitsize */ 655214571Sdim FALSE, /* pc_relative */ 656214571Sdim 1, /* bitpos */ 657214571Sdim complain_overflow_dont,/* complain_on_overflow */ 658214571Sdim bfd_elf_generic_reloc, /* special_function */ 659214571Sdim "R_SCORE16_11", /* name */ 660214571Sdim FALSE, /* partial_inplace */ 661214571Sdim 0x000000ffe, /* src_mask */ 662214571Sdim 0x000000ffe, /* dst_mask */ 663214571Sdim FALSE), /* pcrel_offset */ 664214571Sdim 665214571Sdim /* R_SCORE16_PC8 */ 666214571Sdim HOWTO (R_SCORE16_PC8, /* type */ 667214571Sdim 1, /* rightshift */ 668214571Sdim 1, /* size (0 = byte, 1 = short, 2 = long) */ 669214571Sdim 8, /* bitsize */ 670214571Sdim TRUE, /* pc_relative */ 671214571Sdim 0, /* bitpos */ 672214571Sdim complain_overflow_dont,/* complain_on_overflow */ 673214571Sdim bfd_elf_generic_reloc, /* special_function */ 674214571Sdim "R_SCORE16_PC8", /* name */ 675214571Sdim FALSE, /* partial_inplace */ 676214571Sdim 0x000000ff, /* src_mask */ 677214571Sdim 0x000000ff, /* dst_mask */ 678214571Sdim FALSE), /* pcrel_offset */ 679214571Sdim 680214571Sdim /* 32 bit absolute */ 681214571Sdim HOWTO (R_SCORE_ABS32, /* type 8 */ 682214571Sdim 0, /* rightshift */ 683214571Sdim 2, /* size (0 = byte, 1 = short, 2 = long) */ 684214571Sdim 32, /* bitsize */ 685214571Sdim FALSE, /* pc_relative */ 686214571Sdim 0, /* bitpos */ 687214571Sdim complain_overflow_bitfield, /* complain_on_overflow */ 688214571Sdim bfd_elf_generic_reloc, /* special_function */ 689214571Sdim "R_SCORE_ABS32", /* name */ 690214571Sdim FALSE, /* partial_inplace */ 691214571Sdim 0xffffffff, /* src_mask */ 692214571Sdim 0xffffffff, /* dst_mask */ 693214571Sdim FALSE), /* pcrel_offset */ 694214571Sdim 695214571Sdim /* 16 bit absolute */ 696214571Sdim HOWTO (R_SCORE_ABS16, /* type 11 */ 697214571Sdim 0, /* rightshift */ 698214571Sdim 1, /* size (0 = byte, 1 = short, 2 = long) */ 699214571Sdim 16, /* bitsize */ 700214571Sdim FALSE, /* pc_relative */ 701214571Sdim 0, /* bitpos */ 702214571Sdim complain_overflow_bitfield, /* complain_on_overflow */ 703214571Sdim bfd_elf_generic_reloc, /* special_function */ 704214571Sdim "R_SCORE_ABS16", /* name */ 705214571Sdim FALSE, /* partial_inplace */ 706214571Sdim 0x0000ffff, /* src_mask */ 707214571Sdim 0x0000ffff, /* dst_mask */ 708214571Sdim FALSE), /* pcrel_offset */ 709214571Sdim 710214571Sdim /* R_SCORE_DUMMY2 */ 711214571Sdim HOWTO (R_SCORE_DUMMY2, /* type */ 712214571Sdim 0, /* rightshift */ 713214571Sdim 2, /* size (0 = byte, 1 = short, 2 = long) */ 714214571Sdim 16, /* bitsize */ 715214571Sdim FALSE, /* pc_relative */ 716214571Sdim 0, /* bitpos */ 717214571Sdim complain_overflow_dont,/* complain_on_overflow */ 718214571Sdim bfd_elf_generic_reloc, /* special_function */ 719214571Sdim "R_SCORE_DUMMY2", /* name */ 720214571Sdim TRUE, /* partial_inplace */ 721214571Sdim 0x00007fff, /* src_mask */ 722214571Sdim 0x00007fff, /* dst_mask */ 723214571Sdim FALSE), /* pcrel_offset */ 724214571Sdim 725214571Sdim /* R_SCORE_GP15 */ 726214571Sdim HOWTO (R_SCORE_GP15, /* type */ 727214571Sdim 0, /* rightshift */ 728214571Sdim 2, /* size (0 = byte, 1 = short, 2 = long) */ 729214571Sdim 16, /* bitsize */ 730214571Sdim FALSE, /* pc_relative */ 731214571Sdim 0, /* bitpos */ 732214571Sdim complain_overflow_dont,/* complain_on_overflow */ 733214571Sdim score_elf_gprel15_reloc,/* special_function */ 734214571Sdim "R_SCORE_GP15", /* name */ 735214571Sdim TRUE, /* partial_inplace */ 736214571Sdim 0x00007fff, /* src_mask */ 737214571Sdim 0x00007fff, /* dst_mask */ 738214571Sdim FALSE), /* pcrel_offset */ 739214571Sdim 740214571Sdim /* GNU extension to record C++ vtable hierarchy. */ 741214571Sdim HOWTO (R_SCORE_GNU_VTINHERIT, /* type */ 742214571Sdim 0, /* rightshift */ 743214571Sdim 2, /* size (0 = byte, 1 = short, 2 = long) */ 744214571Sdim 0, /* bitsize */ 745214571Sdim FALSE, /* pc_relative */ 746214571Sdim 0, /* bitpos */ 747214571Sdim complain_overflow_dont,/* complain_on_overflow */ 748214571Sdim NULL, /* special_function */ 749214571Sdim "R_SCORE_GNU_VTINHERIT", /* name */ 750214571Sdim FALSE, /* partial_inplace */ 751214571Sdim 0, /* src_mask */ 752214571Sdim 0, /* dst_mask */ 753214571Sdim FALSE), /* pcrel_offset */ 754214571Sdim 755214571Sdim /* GNU extension to record C++ vtable member usage */ 756214571Sdim HOWTO (R_SCORE_GNU_VTENTRY, /* type */ 757214571Sdim 0, /* rightshift */ 758214571Sdim 2, /* size (0 = byte, 1 = short, 2 = long) */ 759214571Sdim 0, /* bitsize */ 760214571Sdim FALSE, /* pc_relative */ 761214571Sdim 0, /* bitpos */ 762214571Sdim complain_overflow_dont,/* complain_on_overflow */ 763214571Sdim _bfd_elf_rel_vtable_reloc_fn, /* special_function */ 764214571Sdim "R_SCORE_GNU_VTENTRY", /* name */ 765214571Sdim FALSE, /* partial_inplace */ 766214571Sdim 0, /* src_mask */ 767214571Sdim 0, /* dst_mask */ 768214571Sdim FALSE), /* pcrel_offset */ 769214571Sdim 770214571Sdim /* Reference to global offset table. */ 771214571Sdim HOWTO (R_SCORE_GOT15, /* type */ 772214571Sdim 0, /* rightshift */ 773214571Sdim 2, /* size (0 = byte, 1 = short, 2 = long) */ 774214571Sdim 16, /* bitsize */ 775214571Sdim FALSE, /* pc_relative */ 776214571Sdim 0, /* bitpos */ 777214571Sdim complain_overflow_signed, /* complain_on_overflow */ 778214571Sdim score_elf_got15_reloc, /* special_function */ 779214571Sdim "R_SCORE_GOT15", /* name */ 780214571Sdim TRUE, /* partial_inplace */ 781214571Sdim 0x00007fff, /* src_mask */ 782214571Sdim 0x00007fff, /* dst_mask */ 783214571Sdim FALSE), /* pcrel_offset */ 784214571Sdim 785214571Sdim /* Low 16 bits of displacement in global offset table. */ 786214571Sdim HOWTO (R_SCORE_GOT_LO16, /* type */ 787214571Sdim 0, /* rightshift */ 788214571Sdim 2, /* size (0 = byte, 1 = short, 2 = long) */ 789214571Sdim 16, /* bitsize */ 790214571Sdim FALSE, /* pc_relative */ 791214571Sdim 1, /* bitpos */ 792214571Sdim complain_overflow_dont,/* complain_on_overflow */ 793214571Sdim score_elf_got_lo16_reloc, /* special_function */ 794214571Sdim "R_SCORE_GOT_LO16", /* name */ 795214571Sdim TRUE, /* partial_inplace */ 796214571Sdim 0x37ffe, /* src_mask */ 797214571Sdim 0x37ffe, /* dst_mask */ 798214571Sdim FALSE), /* pcrel_offset */ 799214571Sdim 800214571Sdim /* 15 bit call through global offset table. */ 801214571Sdim HOWTO (R_SCORE_CALL15, /* type */ 802214571Sdim 0, /* rightshift */ 803214571Sdim 2, /* size (0 = byte, 1 = short, 2 = long) */ 804214571Sdim 16, /* bitsize */ 805214571Sdim FALSE, /* pc_relative */ 806214571Sdim 0, /* bitpos */ 807214571Sdim complain_overflow_signed, /* complain_on_overflow */ 808214571Sdim bfd_elf_generic_reloc, /* special_function */ 809214571Sdim "R_SCORE_CALL15", /* name */ 810214571Sdim TRUE, /* partial_inplace */ 811214571Sdim 0x0000ffff, /* src_mask */ 812214571Sdim 0x0000ffff, /* dst_mask */ 813214571Sdim FALSE), /* pcrel_offset */ 814214571Sdim 815214571Sdim /* 32 bit GP relative reference. */ 816214571Sdim HOWTO (R_SCORE_GPREL32, /* type */ 817214571Sdim 0, /* rightshift */ 818214571Sdim 2, /* size (0 = byte, 1 = short, 2 = long) */ 819214571Sdim 32, /* bitsize */ 820214571Sdim FALSE, /* pc_relative */ 821214571Sdim 0, /* bitpos */ 822214571Sdim complain_overflow_dont,/* complain_on_overflow */ 823214571Sdim score_elf_gprel32_reloc, /* special_function */ 824214571Sdim "R_SCORE_GPREL32", /* name */ 825214571Sdim TRUE, /* partial_inplace */ 826214571Sdim 0xffffffff, /* src_mask */ 827214571Sdim 0xffffffff, /* dst_mask */ 828214571Sdim FALSE), /* pcrel_offset */ 829214571Sdim 830214571Sdim /* 32 bit symbol relative relocation. */ 831214571Sdim HOWTO (R_SCORE_REL32, /* type */ 832214571Sdim 0, /* rightshift */ 833214571Sdim 2, /* size (0 = byte, 1 = short, 2 = long) */ 834214571Sdim 32, /* bitsize */ 835214571Sdim FALSE, /* pc_relative */ 836214571Sdim 0, /* bitpos */ 837214571Sdim complain_overflow_dont,/* complain_on_overflow */ 838214571Sdim bfd_elf_generic_reloc, /* special_function */ 839214571Sdim "R_SCORE_REL32", /* name */ 840214571Sdim TRUE, /* partial_inplace */ 841214571Sdim 0xffffffff, /* src_mask */ 842214571Sdim 0xffffffff, /* dst_mask */ 843214571Sdim FALSE), /* pcrel_offset */ 844214571Sdim 845214571Sdim /* R_SCORE_DUMMY_HI16 */ 846214571Sdim HOWTO (R_SCORE_DUMMY_HI16, /* type */ 847214571Sdim 0, /* rightshift */ 848214571Sdim 2, /* size (0 = byte, 1 = short, 2 = long) */ 849214571Sdim 16, /* bitsize */ 850214571Sdim FALSE, /* pc_relative */ 851214571Sdim 1, /* bitpos */ 852214571Sdim complain_overflow_dont,/* complain_on_overflow */ 853214571Sdim score_elf_hi16_reloc, /* special_function */ 854214571Sdim "R_SCORE_DUMMY_HI16", /* name */ 855214571Sdim TRUE, /* partial_inplace */ 856214571Sdim 0x37fff, /* src_mask */ 857214571Sdim 0x37fff, /* dst_mask */ 858214571Sdim FALSE), /* pcrel_offset */ 859214571Sdim}; 860214571Sdim 861214571Sdimstruct score_reloc_map 862214571Sdim{ 863214571Sdim bfd_reloc_code_real_type bfd_reloc_val; 864214571Sdim unsigned char elf_reloc_val; 865214571Sdim}; 866214571Sdim 867214571Sdimstatic const struct score_reloc_map elf32_score_reloc_map[] = 868214571Sdim{ 869214571Sdim {BFD_RELOC_NONE, R_SCORE_NONE}, 870214571Sdim {BFD_RELOC_HI16_S, R_SCORE_HI16}, 871214571Sdim {BFD_RELOC_LO16, R_SCORE_LO16}, 872214571Sdim {BFD_RELOC_SCORE_DUMMY1, R_SCORE_DUMMY1}, 873214571Sdim {BFD_RELOC_SCORE_JMP, R_SCORE_24}, 874214571Sdim {BFD_RELOC_SCORE_BRANCH, R_SCORE_PC19}, 875214571Sdim {BFD_RELOC_SCORE16_JMP, R_SCORE16_11}, 876214571Sdim {BFD_RELOC_SCORE16_BRANCH, R_SCORE16_PC8}, 877214571Sdim {BFD_RELOC_32, R_SCORE_ABS32}, 878214571Sdim {BFD_RELOC_16, R_SCORE_ABS16}, 879214571Sdim {BFD_RELOC_SCORE_DUMMY2, R_SCORE_DUMMY2}, 880214571Sdim {BFD_RELOC_SCORE_GPREL15, R_SCORE_GP15}, 881214571Sdim {BFD_RELOC_VTABLE_INHERIT, R_SCORE_GNU_VTINHERIT}, 882214571Sdim {BFD_RELOC_VTABLE_ENTRY, R_SCORE_GNU_VTENTRY}, 883214571Sdim {BFD_RELOC_SCORE_GOT15, R_SCORE_GOT15}, 884214571Sdim {BFD_RELOC_SCORE_GOT_LO16, R_SCORE_GOT_LO16}, 885214571Sdim {BFD_RELOC_SCORE_CALL15, R_SCORE_CALL15}, 886214571Sdim {BFD_RELOC_GPREL32, R_SCORE_GPREL32}, 887214571Sdim {BFD_RELOC_32_PCREL, R_SCORE_REL32}, 888214571Sdim {BFD_RELOC_SCORE_DUMMY_HI16, R_SCORE_DUMMY_HI16}, 889214571Sdim}; 890214571Sdim 891214571Sdim/* got_entries only match if they're identical, except for gotidx, so 892214571Sdim use all fields to compute the hash, and compare the appropriate 893214571Sdim union members. */ 894214571Sdim 895214571Sdimstatic hashval_t 896214571Sdimscore_elf_got_entry_hash (const void *entry_) 897214571Sdim{ 898214571Sdim const struct score_got_entry *entry = (struct score_got_entry *)entry_; 899214571Sdim 900214571Sdim return entry->symndx 901214571Sdim + (!entry->abfd ? entry->d.address : entry->abfd->id); 902214571Sdim} 903214571Sdim 904214571Sdimstatic int 905214571Sdimscore_elf_got_entry_eq (const void *entry1, const void *entry2) 906214571Sdim{ 907214571Sdim const struct score_got_entry *e1 = (struct score_got_entry *)entry1; 908214571Sdim const struct score_got_entry *e2 = (struct score_got_entry *)entry2; 909214571Sdim 910214571Sdim return e1->abfd == e2->abfd && e1->symndx == e2->symndx 911214571Sdim && (! e1->abfd ? e1->d.address == e2->d.address 912214571Sdim : e1->symndx >= 0 ? e1->d.addend == e2->d.addend 913214571Sdim : e1->d.h == e2->d.h); 914214571Sdim} 915214571Sdim 916214571Sdim/* If H needs a GOT entry, assign it the highest available dynamic 917214571Sdim index. Otherwise, assign it the lowest available dynamic 918214571Sdim index. */ 919214571Sdim 920214571Sdimstatic bfd_boolean 921214571Sdimscore_elf_sort_hash_table_f (struct score_elf_link_hash_entry *h, void *data) 922214571Sdim{ 923214571Sdim struct score_elf_hash_sort_data *hsd = data; 924214571Sdim 925214571Sdim if (h->root.root.type == bfd_link_hash_warning) 926214571Sdim h = (struct score_elf_link_hash_entry *) h->root.root.u.i.link; 927214571Sdim 928214571Sdim /* Symbols without dynamic symbol table entries aren't interesting at all. */ 929214571Sdim if (h->root.dynindx == -1) 930214571Sdim return TRUE; 931214571Sdim 932214571Sdim /* Global symbols that need GOT entries that are not explicitly 933214571Sdim referenced are marked with got offset 2. Those that are 934214571Sdim referenced get a 1, and those that don't need GOT entries get 935214571Sdim -1. */ 936214571Sdim if (h->root.got.offset == 2) 937214571Sdim { 938214571Sdim if (hsd->max_unref_got_dynindx == hsd->min_got_dynindx) 939214571Sdim hsd->low = (struct elf_link_hash_entry *) h; 940214571Sdim h->root.dynindx = hsd->max_unref_got_dynindx++; 941214571Sdim } 942214571Sdim else if (h->root.got.offset != 1) 943214571Sdim h->root.dynindx = hsd->max_non_got_dynindx++; 944214571Sdim else 945214571Sdim { 946214571Sdim h->root.dynindx = --hsd->min_got_dynindx; 947214571Sdim hsd->low = (struct elf_link_hash_entry *) h; 948214571Sdim } 949214571Sdim 950214571Sdim return TRUE; 951214571Sdim} 952214571Sdim 953214571Sdimstatic asection * 954214571Sdimscore_elf_got_section (bfd *abfd, bfd_boolean maybe_excluded) 955214571Sdim{ 956214571Sdim asection *sgot = bfd_get_section_by_name (abfd, ".got"); 957214571Sdim 958214571Sdim if (sgot == NULL || (! maybe_excluded && (sgot->flags & SEC_EXCLUDE) != 0)) 959214571Sdim return NULL; 960214571Sdim return sgot; 961214571Sdim} 962214571Sdim 963214571Sdim/* Returns the GOT information associated with the link indicated by 964214571Sdim INFO. If SGOTP is non-NULL, it is filled in with the GOT section. */ 965214571Sdim 966214571Sdimstatic struct score_got_info * 967214571Sdimscore_elf_got_info (bfd *abfd, asection **sgotp) 968214571Sdim{ 969214571Sdim asection *sgot; 970214571Sdim struct score_got_info *g; 971214571Sdim 972214571Sdim sgot = score_elf_got_section (abfd, TRUE); 973214571Sdim BFD_ASSERT (sgot != NULL); 974214571Sdim BFD_ASSERT (elf_section_data (sgot) != NULL); 975214571Sdim g = score_elf_section_data (sgot)->u.got_info; 976214571Sdim BFD_ASSERT (g != NULL); 977214571Sdim 978214571Sdim if (sgotp) 979214571Sdim *sgotp = sgot; 980214571Sdim return g; 981214571Sdim} 982214571Sdim 983214571Sdim/* Sort the dynamic symbol table so that symbols that need GOT entries 984214571Sdim appear towards the end. This reduces the amount of GOT space 985214571Sdim required. MAX_LOCAL is used to set the number of local symbols 986214571Sdim known to be in the dynamic symbol table. During 987214571Sdim _bfd_score_elf_size_dynamic_sections, this value is 1. Afterward, the 988214571Sdim section symbols are added and the count is higher. */ 989214571Sdim 990214571Sdimstatic bfd_boolean 991214571Sdimscore_elf_sort_hash_table (struct bfd_link_info *info, 992214571Sdim unsigned long max_local) 993214571Sdim{ 994214571Sdim struct score_elf_hash_sort_data hsd; 995214571Sdim struct score_got_info *g; 996214571Sdim bfd *dynobj; 997214571Sdim 998214571Sdim dynobj = elf_hash_table (info)->dynobj; 999214571Sdim 1000214571Sdim g = score_elf_got_info (dynobj, NULL); 1001214571Sdim 1002214571Sdim hsd.low = NULL; 1003214571Sdim hsd.max_unref_got_dynindx = 1004214571Sdim hsd.min_got_dynindx = elf_hash_table (info)->dynsymcount 1005214571Sdim /* In the multi-got case, assigned_gotno of the master got_info 1006214571Sdim indicate the number of entries that aren't referenced in the 1007214571Sdim primary GOT, but that must have entries because there are 1008214571Sdim dynamic relocations that reference it. Since they aren't 1009214571Sdim referenced, we move them to the end of the GOT, so that they 1010214571Sdim don't prevent other entries that are referenced from getting 1011214571Sdim too large offsets. */ 1012214571Sdim - (g->next ? g->assigned_gotno : 0); 1013214571Sdim hsd.max_non_got_dynindx = max_local; 1014214571Sdim score_elf_link_hash_traverse (((struct score_elf_link_hash_table *) 1015214571Sdim elf_hash_table (info)), 1016214571Sdim score_elf_sort_hash_table_f, 1017214571Sdim &hsd); 1018214571Sdim 1019214571Sdim /* There should have been enough room in the symbol table to 1020214571Sdim accommodate both the GOT and non-GOT symbols. */ 1021214571Sdim BFD_ASSERT (hsd.max_non_got_dynindx <= hsd.min_got_dynindx); 1022214571Sdim BFD_ASSERT ((unsigned long)hsd.max_unref_got_dynindx 1023214571Sdim <= elf_hash_table (info)->dynsymcount); 1024214571Sdim 1025214571Sdim /* Now we know which dynamic symbol has the lowest dynamic symbol 1026214571Sdim table index in the GOT. */ 1027214571Sdim g->global_gotsym = hsd.low; 1028214571Sdim 1029214571Sdim return TRUE; 1030214571Sdim} 1031214571Sdim 1032214571Sdim/* Create an entry in an score ELF linker hash table. */ 1033214571Sdim 1034214571Sdimstatic struct bfd_hash_entry * 1035214571Sdimscore_elf_link_hash_newfunc (struct bfd_hash_entry *entry, 1036214571Sdim struct bfd_hash_table *table, 1037214571Sdim const char *string) 1038214571Sdim{ 1039214571Sdim struct score_elf_link_hash_entry *ret = (struct score_elf_link_hash_entry *)entry; 1040214571Sdim 1041214571Sdim /* Allocate the structure if it has not already been allocated by a subclass. */ 1042214571Sdim if (ret == NULL) 1043214571Sdim ret = bfd_hash_allocate (table, sizeof (struct score_elf_link_hash_entry)); 1044214571Sdim if (ret == NULL) 1045214571Sdim return (struct bfd_hash_entry *)ret; 1046214571Sdim 1047214571Sdim /* Call the allocation method of the superclass. */ 1048214571Sdim ret = ((struct score_elf_link_hash_entry *) 1049214571Sdim _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *)ret, table, string)); 1050214571Sdim 1051214571Sdim if (ret != NULL) 1052214571Sdim { 1053214571Sdim ret->possibly_dynamic_relocs = 0; 1054214571Sdim ret->readonly_reloc = FALSE; 1055214571Sdim ret->no_fn_stub = FALSE; 1056214571Sdim ret->forced_local = FALSE; 1057214571Sdim } 1058214571Sdim 1059214571Sdim return (struct bfd_hash_entry *)ret; 1060214571Sdim} 1061214571Sdim 1062214571Sdim/* Returns the first relocation of type r_type found, beginning with 1063214571Sdim RELOCATION. RELEND is one-past-the-end of the relocation table. */ 1064214571Sdim 1065214571Sdimstatic const Elf_Internal_Rela * 1066214571Sdimscore_elf_next_relocation (bfd *abfd ATTRIBUTE_UNUSED, unsigned int r_type, 1067214571Sdim const Elf_Internal_Rela *relocation, 1068214571Sdim const Elf_Internal_Rela *relend) 1069214571Sdim{ 1070214571Sdim while (relocation < relend) 1071214571Sdim { 1072214571Sdim if (ELF32_R_TYPE (relocation->r_info) == r_type) 1073214571Sdim return relocation; 1074214571Sdim 1075214571Sdim ++relocation; 1076214571Sdim } 1077214571Sdim 1078214571Sdim /* We didn't find it. */ 1079214571Sdim bfd_set_error (bfd_error_bad_value); 1080214571Sdim return NULL; 1081214571Sdim} 1082214571Sdim 1083214571Sdim/* This function is called via qsort() to sort the dynamic relocation 1084214571Sdim entries by increasing r_symndx value. */ 1085214571Sdim 1086214571Sdimstatic int 1087214571Sdimscore_elf_sort_dynamic_relocs (const void *arg1, const void *arg2) 1088214571Sdim{ 1089214571Sdim Elf_Internal_Rela int_reloc1; 1090214571Sdim Elf_Internal_Rela int_reloc2; 1091214571Sdim 1092214571Sdim bfd_elf32_swap_reloc_in (reldyn_sorting_bfd, arg1, &int_reloc1); 1093214571Sdim bfd_elf32_swap_reloc_in (reldyn_sorting_bfd, arg2, &int_reloc2); 1094214571Sdim 1095214571Sdim return (ELF32_R_SYM (int_reloc1.r_info) - ELF32_R_SYM (int_reloc2.r_info)); 1096214571Sdim} 1097214571Sdim 1098214571Sdim/* Return whether a relocation is against a local symbol. */ 1099214571Sdim 1100214571Sdimstatic bfd_boolean 1101214571Sdimscore_elf_local_relocation_p (bfd *input_bfd, 1102214571Sdim const Elf_Internal_Rela *relocation, 1103214571Sdim asection **local_sections, 1104214571Sdim bfd_boolean check_forced) 1105214571Sdim{ 1106214571Sdim unsigned long r_symndx; 1107214571Sdim Elf_Internal_Shdr *symtab_hdr; 1108214571Sdim struct score_elf_link_hash_entry *h; 1109214571Sdim size_t extsymoff; 1110214571Sdim 1111214571Sdim r_symndx = ELF32_R_SYM (relocation->r_info); 1112214571Sdim symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; 1113214571Sdim extsymoff = (elf_bad_symtab (input_bfd)) ? 0 : symtab_hdr->sh_info; 1114214571Sdim 1115214571Sdim if (r_symndx < extsymoff) 1116214571Sdim return TRUE; 1117214571Sdim if (elf_bad_symtab (input_bfd) && local_sections[r_symndx] != NULL) 1118214571Sdim return TRUE; 1119214571Sdim 1120214571Sdim if (check_forced) 1121214571Sdim { 1122214571Sdim /* Look up the hash table to check whether the symbol was forced local. */ 1123214571Sdim h = (struct score_elf_link_hash_entry *) 1124214571Sdim elf_sym_hashes (input_bfd) [r_symndx - extsymoff]; 1125214571Sdim /* Find the real hash-table entry for this symbol. */ 1126214571Sdim while (h->root.root.type == bfd_link_hash_indirect 1127214571Sdim || h->root.root.type == bfd_link_hash_warning) 1128214571Sdim h = (struct score_elf_link_hash_entry *) h->root.root.u.i.link; 1129214571Sdim if (h->root.forced_local) 1130214571Sdim return TRUE; 1131214571Sdim } 1132214571Sdim 1133214571Sdim return FALSE; 1134214571Sdim} 1135214571Sdim 1136214571Sdim/* Returns the dynamic relocation section for DYNOBJ. */ 1137214571Sdim 1138214571Sdimstatic asection * 1139214571Sdimscore_elf_rel_dyn_section (bfd *dynobj, bfd_boolean create_p) 1140214571Sdim{ 1141214571Sdim static const char dname[] = ".rel.dyn"; 1142214571Sdim asection *sreloc; 1143214571Sdim 1144214571Sdim sreloc = bfd_get_section_by_name (dynobj, dname); 1145214571Sdim if (sreloc == NULL && create_p) 1146214571Sdim { 1147214571Sdim sreloc = bfd_make_section_with_flags (dynobj, dname, 1148214571Sdim (SEC_ALLOC 1149214571Sdim | SEC_LOAD 1150214571Sdim | SEC_HAS_CONTENTS 1151214571Sdim | SEC_IN_MEMORY 1152214571Sdim | SEC_LINKER_CREATED 1153214571Sdim | SEC_READONLY)); 1154214571Sdim if (sreloc == NULL 1155214571Sdim || ! bfd_set_section_alignment (dynobj, sreloc, 1156214571Sdim SCORE_ELF_LOG_FILE_ALIGN (dynobj))) 1157214571Sdim return NULL; 1158214571Sdim } 1159214571Sdim return sreloc; 1160214571Sdim} 1161214571Sdim 1162214571Sdimstatic void 1163214571Sdimscore_elf_allocate_dynamic_relocations (bfd *abfd, unsigned int n) 1164214571Sdim{ 1165214571Sdim asection *s; 1166214571Sdim 1167214571Sdim s = score_elf_rel_dyn_section (abfd, FALSE); 1168214571Sdim BFD_ASSERT (s != NULL); 1169214571Sdim 1170214571Sdim if (s->size == 0) 1171214571Sdim { 1172214571Sdim /* Make room for a null element. */ 1173214571Sdim s->size += SCORE_ELF_REL_SIZE (abfd); 1174214571Sdim ++s->reloc_count; 1175214571Sdim } 1176214571Sdim s->size += n * SCORE_ELF_REL_SIZE (abfd); 1177214571Sdim} 1178214571Sdim 1179214571Sdim/* Create a rel.dyn relocation for the dynamic linker to resolve. REL 1180214571Sdim is the original relocation, which is now being transformed into a 1181214571Sdim dynamic relocation. The ADDENDP is adjusted if necessary; the 1182214571Sdim caller should store the result in place of the original addend. */ 1183214571Sdim 1184214571Sdimstatic bfd_boolean 1185214571Sdimscore_elf_create_dynamic_relocation (bfd *output_bfd, 1186214571Sdim struct bfd_link_info *info, 1187214571Sdim const Elf_Internal_Rela *rel, 1188214571Sdim struct score_elf_link_hash_entry *h, 1189214571Sdim bfd_vma symbol, 1190214571Sdim bfd_vma *addendp, asection *input_section) 1191214571Sdim{ 1192214571Sdim Elf_Internal_Rela outrel[3]; 1193214571Sdim asection *sreloc; 1194214571Sdim bfd *dynobj; 1195214571Sdim int r_type; 1196214571Sdim long indx; 1197214571Sdim bfd_boolean defined_p; 1198214571Sdim 1199214571Sdim r_type = ELF32_R_TYPE (rel->r_info); 1200214571Sdim dynobj = elf_hash_table (info)->dynobj; 1201214571Sdim sreloc = score_elf_rel_dyn_section (dynobj, FALSE); 1202214571Sdim BFD_ASSERT (sreloc != NULL); 1203214571Sdim BFD_ASSERT (sreloc->contents != NULL); 1204214571Sdim BFD_ASSERT (sreloc->reloc_count * SCORE_ELF_REL_SIZE (output_bfd) < sreloc->size); 1205214571Sdim 1206214571Sdim outrel[0].r_offset = 1207214571Sdim _bfd_elf_section_offset (output_bfd, info, input_section, rel[0].r_offset); 1208214571Sdim outrel[1].r_offset = 1209214571Sdim _bfd_elf_section_offset (output_bfd, info, input_section, rel[1].r_offset); 1210214571Sdim outrel[2].r_offset = 1211214571Sdim _bfd_elf_section_offset (output_bfd, info, input_section, rel[2].r_offset); 1212214571Sdim 1213214571Sdim if (outrel[0].r_offset == MINUS_ONE) 1214214571Sdim /* The relocation field has been deleted. */ 1215214571Sdim return TRUE; 1216214571Sdim 1217214571Sdim if (outrel[0].r_offset == MINUS_TWO) 1218214571Sdim { 1219214571Sdim /* The relocation field has been converted into a relative value of 1220214571Sdim some sort. Functions like _bfd_elf_write_section_eh_frame expect 1221214571Sdim the field to be fully relocated, so add in the symbol's value. */ 1222214571Sdim *addendp += symbol; 1223214571Sdim return TRUE; 1224214571Sdim } 1225214571Sdim 1226214571Sdim /* We must now calculate the dynamic symbol table index to use 1227214571Sdim in the relocation. */ 1228214571Sdim if (h != NULL 1229214571Sdim && (! info->symbolic || !h->root.def_regular) 1230214571Sdim /* h->root.dynindx may be -1 if this symbol was marked to 1231214571Sdim become local. */ 1232214571Sdim && h->root.dynindx != -1) 1233214571Sdim { 1234214571Sdim indx = h->root.dynindx; 1235214571Sdim /* ??? glibc's ld.so just adds the final GOT entry to the 1236214571Sdim relocation field. It therefore treats relocs against 1237214571Sdim defined symbols in the same way as relocs against 1238214571Sdim undefined symbols. */ 1239214571Sdim defined_p = FALSE; 1240214571Sdim } 1241214571Sdim else 1242214571Sdim { 1243214571Sdim indx = 0; 1244214571Sdim defined_p = TRUE; 1245214571Sdim } 1246214571Sdim 1247214571Sdim /* If the relocation was previously an absolute relocation and 1248214571Sdim this symbol will not be referred to by the relocation, we must 1249214571Sdim adjust it by the value we give it in the dynamic symbol table. 1250214571Sdim Otherwise leave the job up to the dynamic linker. */ 1251214571Sdim if (defined_p && r_type != R_SCORE_REL32) 1252214571Sdim *addendp += symbol; 1253214571Sdim 1254214571Sdim /* The relocation is always an REL32 relocation because we don't 1255214571Sdim know where the shared library will wind up at load-time. */ 1256214571Sdim outrel[0].r_info = ELF32_R_INFO ((unsigned long) indx, R_SCORE_REL32); 1257214571Sdim 1258214571Sdim /* For strict adherence to the ABI specification, we should 1259214571Sdim generate a R_SCORE_64 relocation record by itself before the 1260214571Sdim _REL32/_64 record as well, such that the addend is read in as 1261214571Sdim a 64-bit value (REL32 is a 32-bit relocation, after all). 1262214571Sdim However, since none of the existing ELF64 SCORE dynamic 1263214571Sdim loaders seems to care, we don't waste space with these 1264214571Sdim artificial relocations. If this turns out to not be true, 1265214571Sdim score_elf_allocate_dynamic_relocations() should be tweaked so 1266214571Sdim as to make room for a pair of dynamic relocations per 1267214571Sdim invocation if ABI_64_P, and here we should generate an 1268214571Sdim additional relocation record with R_SCORE_64 by itself for a 1269214571Sdim NULL symbol before this relocation record. */ 1270214571Sdim outrel[1].r_info = ELF32_R_INFO (0, R_SCORE_NONE); 1271214571Sdim outrel[2].r_info = ELF32_R_INFO (0, R_SCORE_NONE); 1272214571Sdim 1273214571Sdim /* Adjust the output offset of the relocation to reference the 1274214571Sdim correct location in the output file. */ 1275214571Sdim outrel[0].r_offset += (input_section->output_section->vma 1276214571Sdim + input_section->output_offset); 1277214571Sdim outrel[1].r_offset += (input_section->output_section->vma 1278214571Sdim + input_section->output_offset); 1279214571Sdim outrel[2].r_offset += (input_section->output_section->vma 1280214571Sdim + input_section->output_offset); 1281214571Sdim 1282214571Sdim /* Put the relocation back out. We have to use the special 1283214571Sdim relocation outputter in the 64-bit case since the 64-bit 1284214571Sdim relocation format is non-standard. */ 1285214571Sdim bfd_elf32_swap_reloc_out 1286214571Sdim (output_bfd, &outrel[0], 1287214571Sdim (sreloc->contents + sreloc->reloc_count * sizeof (Elf32_External_Rel))); 1288214571Sdim 1289214571Sdim /* We've now added another relocation. */ 1290214571Sdim ++sreloc->reloc_count; 1291214571Sdim 1292214571Sdim /* Make sure the output section is writable. The dynamic linker 1293214571Sdim will be writing to it. */ 1294214571Sdim elf_section_data (input_section->output_section)->this_hdr.sh_flags |= SHF_WRITE; 1295214571Sdim 1296214571Sdim return TRUE; 1297214571Sdim} 1298214571Sdim 1299214571Sdimstatic bfd_boolean 1300214571Sdimscore_elf_create_got_section (bfd *abfd, 1301214571Sdim struct bfd_link_info *info, 1302214571Sdim bfd_boolean maybe_exclude) 1303214571Sdim{ 1304214571Sdim flagword flags; 1305214571Sdim asection *s; 1306214571Sdim struct elf_link_hash_entry *h; 1307214571Sdim struct bfd_link_hash_entry *bh; 1308214571Sdim struct score_got_info *g; 1309214571Sdim bfd_size_type amt; 1310214571Sdim 1311214571Sdim /* This function may be called more than once. */ 1312214571Sdim s = score_elf_got_section (abfd, TRUE); 1313214571Sdim if (s) 1314214571Sdim { 1315214571Sdim if (! maybe_exclude) 1316214571Sdim s->flags &= ~SEC_EXCLUDE; 1317214571Sdim return TRUE; 1318214571Sdim } 1319214571Sdim 1320214571Sdim flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED); 1321214571Sdim 1322214571Sdim if (maybe_exclude) 1323214571Sdim flags |= SEC_EXCLUDE; 1324214571Sdim 1325214571Sdim /* We have to use an alignment of 2**4 here because this is hardcoded 1326214571Sdim in the function stub generation and in the linker script. */ 1327214571Sdim s = bfd_make_section_with_flags (abfd, ".got", flags); 1328214571Sdim if (s == NULL 1329214571Sdim || ! bfd_set_section_alignment (abfd, s, 4)) 1330214571Sdim return FALSE; 1331214571Sdim 1332214571Sdim /* Define the symbol _GLOBAL_OFFSET_TABLE_. We don't do this in the 1333214571Sdim linker script because we don't want to define the symbol if we 1334214571Sdim are not creating a global offset table. */ 1335214571Sdim bh = NULL; 1336214571Sdim if (! (_bfd_generic_link_add_one_symbol 1337214571Sdim (info, abfd, "_GLOBAL_OFFSET_TABLE_", BSF_GLOBAL, s, 1338214571Sdim 0, NULL, FALSE, get_elf_backend_data (abfd)->collect, &bh))) 1339214571Sdim return FALSE; 1340214571Sdim 1341214571Sdim h = (struct elf_link_hash_entry *) bh; 1342214571Sdim h->non_elf = 0; 1343214571Sdim h->def_regular = 1; 1344214571Sdim h->type = STT_OBJECT; 1345214571Sdim 1346214571Sdim if (info->shared && ! bfd_elf_link_record_dynamic_symbol (info, h)) 1347214571Sdim return FALSE; 1348214571Sdim 1349214571Sdim amt = sizeof (struct score_got_info); 1350214571Sdim g = bfd_alloc (abfd, amt); 1351214571Sdim if (g == NULL) 1352214571Sdim return FALSE; 1353214571Sdim 1354214571Sdim g->global_gotsym = NULL; 1355214571Sdim g->global_gotno = 0; 1356214571Sdim 1357214571Sdim g->local_gotno = SCORE_RESERVED_GOTNO; 1358214571Sdim g->assigned_gotno = SCORE_RESERVED_GOTNO; 1359214571Sdim g->next = NULL; 1360214571Sdim 1361214571Sdim g->got_entries = htab_try_create (1, score_elf_got_entry_hash, 1362214571Sdim score_elf_got_entry_eq, NULL); 1363214571Sdim if (g->got_entries == NULL) 1364214571Sdim return FALSE; 1365214571Sdim score_elf_section_data (s)->u.got_info = g; 1366214571Sdim score_elf_section_data (s)->elf.this_hdr.sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_SCORE_GPREL; 1367214571Sdim 1368214571Sdim return TRUE; 1369214571Sdim} 1370214571Sdim 1371214571Sdim/* Calculate the %high function. */ 1372214571Sdim 1373214571Sdimstatic bfd_vma 1374214571Sdimscore_elf_high (bfd_vma value) 1375214571Sdim{ 1376214571Sdim return ((value + (bfd_vma) 0x8000) >> 16) & 0xffff; 1377214571Sdim} 1378214571Sdim 1379214571Sdim/* Create a local GOT entry for VALUE. Return the index of the entry, 1380214571Sdim or -1 if it could not be created. */ 1381214571Sdim 1382214571Sdimstatic struct score_got_entry * 1383214571Sdimscore_elf_create_local_got_entry (bfd *abfd, 1384214571Sdim bfd *ibfd ATTRIBUTE_UNUSED, 1385214571Sdim struct score_got_info *gg, 1386214571Sdim asection *sgot, bfd_vma value, 1387214571Sdim unsigned long r_symndx ATTRIBUTE_UNUSED, 1388214571Sdim struct score_elf_link_hash_entry *h ATTRIBUTE_UNUSED, 1389214571Sdim int r_type ATTRIBUTE_UNUSED) 1390214571Sdim{ 1391214571Sdim struct score_got_entry entry, **loc; 1392214571Sdim struct score_got_info *g; 1393214571Sdim 1394214571Sdim entry.abfd = NULL; 1395214571Sdim entry.symndx = -1; 1396214571Sdim entry.d.address = value; 1397214571Sdim 1398214571Sdim g = gg; 1399214571Sdim loc = (struct score_got_entry **) htab_find_slot (g->got_entries, &entry, INSERT); 1400214571Sdim if (*loc) 1401214571Sdim return *loc; 1402214571Sdim 1403214571Sdim entry.gotidx = SCORE_ELF_GOT_SIZE (abfd) * g->assigned_gotno++; 1404214571Sdim 1405214571Sdim *loc = bfd_alloc (abfd, sizeof entry); 1406214571Sdim 1407214571Sdim if (! *loc) 1408214571Sdim return NULL; 1409214571Sdim 1410214571Sdim memcpy (*loc, &entry, sizeof entry); 1411214571Sdim 1412214571Sdim if (g->assigned_gotno >= g->local_gotno) 1413214571Sdim { 1414214571Sdim (*loc)->gotidx = -1; 1415214571Sdim /* We didn't allocate enough space in the GOT. */ 1416214571Sdim (*_bfd_error_handler) 1417214571Sdim (_("not enough GOT space for local GOT entries")); 1418214571Sdim bfd_set_error (bfd_error_bad_value); 1419214571Sdim return NULL; 1420214571Sdim } 1421214571Sdim 1422214571Sdim bfd_put_32 (abfd, value, (sgot->contents + entry.gotidx)); 1423214571Sdim 1424214571Sdim return *loc; 1425214571Sdim} 1426214571Sdim 1427214571Sdim/* Find a GOT entry whose higher-order 16 bits are the same as those 1428214571Sdim for value. Return the index into the GOT for this entry. */ 1429214571Sdim 1430214571Sdimstatic bfd_vma 1431214571Sdimscore_elf_got16_entry (bfd *abfd, bfd *ibfd, struct bfd_link_info *info, 1432214571Sdim bfd_vma value, bfd_boolean external) 1433214571Sdim{ 1434214571Sdim asection *sgot; 1435214571Sdim struct score_got_info *g; 1436214571Sdim struct score_got_entry *entry; 1437214571Sdim 1438214571Sdim if (!external) 1439214571Sdim { 1440214571Sdim /* Although the ABI says that it is "the high-order 16 bits" that we 1441214571Sdim want, it is really the %high value. The complete value is 1442214571Sdim calculated with a `addiu' of a LO16 relocation, just as with a 1443214571Sdim HI16/LO16 pair. */ 1444214571Sdim value = score_elf_high (value) << 16; 1445214571Sdim } 1446214571Sdim 1447214571Sdim g = score_elf_got_info (elf_hash_table (info)->dynobj, &sgot); 1448214571Sdim 1449214571Sdim entry = score_elf_create_local_got_entry (abfd, ibfd, g, sgot, value, 0, NULL, 1450214571Sdim R_SCORE_GOT15); 1451214571Sdim if (entry) 1452214571Sdim return entry->gotidx; 1453214571Sdim else 1454214571Sdim return MINUS_ONE; 1455214571Sdim} 1456214571Sdim 1457214571Sdimstatic void 1458214571Sdim_bfd_score_elf_hide_symbol (struct bfd_link_info *info, 1459214571Sdim struct elf_link_hash_entry *entry, 1460214571Sdim bfd_boolean force_local) 1461214571Sdim{ 1462214571Sdim bfd *dynobj; 1463214571Sdim asection *got; 1464214571Sdim struct score_got_info *g; 1465214571Sdim struct score_elf_link_hash_entry *h; 1466214571Sdim 1467214571Sdim h = (struct score_elf_link_hash_entry *) entry; 1468214571Sdim if (h->forced_local) 1469214571Sdim return; 1470214571Sdim h->forced_local = TRUE; 1471214571Sdim 1472214571Sdim dynobj = elf_hash_table (info)->dynobj; 1473214571Sdim if (dynobj != NULL && force_local) 1474214571Sdim { 1475214571Sdim got = score_elf_got_section (dynobj, FALSE); 1476214571Sdim if (got == NULL) 1477214571Sdim return; 1478214571Sdim g = score_elf_section_data (got)->u.got_info; 1479214571Sdim 1480214571Sdim if (g->next) 1481214571Sdim { 1482214571Sdim struct score_got_entry e; 1483214571Sdim struct score_got_info *gg = g; 1484214571Sdim 1485214571Sdim /* Since we're turning what used to be a global symbol into a 1486214571Sdim local one, bump up the number of local entries of each GOT 1487214571Sdim that had an entry for it. This will automatically decrease 1488214571Sdim the number of global entries, since global_gotno is actually 1489214571Sdim the upper limit of global entries. */ 1490214571Sdim e.abfd = dynobj; 1491214571Sdim e.symndx = -1; 1492214571Sdim e.d.h = h; 1493214571Sdim 1494214571Sdim for (g = g->next; g != gg; g = g->next) 1495214571Sdim if (htab_find (g->got_entries, &e)) 1496214571Sdim { 1497214571Sdim BFD_ASSERT (g->global_gotno > 0); 1498214571Sdim g->local_gotno++; 1499214571Sdim g->global_gotno--; 1500214571Sdim } 1501214571Sdim 1502214571Sdim /* If this was a global symbol forced into the primary GOT, we 1503214571Sdim no longer need an entry for it. We can't release the entry 1504214571Sdim at this point, but we must at least stop counting it as one 1505214571Sdim of the symbols that required a forced got entry. */ 1506214571Sdim if (h->root.got.offset == 2) 1507214571Sdim { 1508214571Sdim BFD_ASSERT (gg->assigned_gotno > 0); 1509214571Sdim gg->assigned_gotno--; 1510214571Sdim } 1511214571Sdim } 1512214571Sdim else if (g->global_gotno == 0 && g->global_gotsym == NULL) 1513214571Sdim /* If we haven't got through GOT allocation yet, just bump up the 1514214571Sdim number of local entries, as this symbol won't be counted as 1515214571Sdim global. */ 1516214571Sdim g->local_gotno++; 1517214571Sdim else if (h->root.got.offset == 1) 1518214571Sdim { 1519214571Sdim /* If we're past non-multi-GOT allocation and this symbol had 1520214571Sdim been marked for a global got entry, give it a local entry 1521214571Sdim instead. */ 1522214571Sdim BFD_ASSERT (g->global_gotno > 0); 1523214571Sdim g->local_gotno++; 1524214571Sdim g->global_gotno--; 1525214571Sdim } 1526214571Sdim } 1527214571Sdim 1528214571Sdim _bfd_elf_link_hash_hide_symbol (info, &h->root, force_local); 1529214571Sdim} 1530214571Sdim 1531214571Sdim/* If H is a symbol that needs a global GOT entry, but has a dynamic 1532214571Sdim symbol table index lower than any we've seen to date, record it for 1533214571Sdim posterity. */ 1534214571Sdim 1535214571Sdimstatic bfd_boolean 1536214571Sdimscore_elf_record_global_got_symbol (struct elf_link_hash_entry *h, 1537214571Sdim bfd *abfd, 1538214571Sdim struct bfd_link_info *info, 1539214571Sdim struct score_got_info *g) 1540214571Sdim{ 1541214571Sdim struct score_got_entry entry, **loc; 1542214571Sdim 1543214571Sdim /* A global symbol in the GOT must also be in the dynamic symbol table. */ 1544214571Sdim if (h->dynindx == -1) 1545214571Sdim { 1546214571Sdim switch (ELF_ST_VISIBILITY (h->other)) 1547214571Sdim { 1548214571Sdim case STV_INTERNAL: 1549214571Sdim case STV_HIDDEN: 1550214571Sdim _bfd_score_elf_hide_symbol (info, h, TRUE); 1551214571Sdim break; 1552214571Sdim } 1553214571Sdim if (!bfd_elf_link_record_dynamic_symbol (info, h)) 1554214571Sdim return FALSE; 1555214571Sdim } 1556214571Sdim 1557214571Sdim entry.abfd = abfd; 1558214571Sdim entry.symndx = -1; 1559214571Sdim entry.d.h = (struct score_elf_link_hash_entry *)h; 1560214571Sdim 1561214571Sdim loc = (struct score_got_entry **)htab_find_slot (g->got_entries, &entry, INSERT); 1562214571Sdim 1563214571Sdim /* If we've already marked this entry as needing GOT space, we don't 1564214571Sdim need to do it again. */ 1565214571Sdim if (*loc) 1566214571Sdim return TRUE; 1567214571Sdim 1568214571Sdim *loc = bfd_alloc (abfd, sizeof entry); 1569214571Sdim if (! *loc) 1570214571Sdim return FALSE; 1571214571Sdim 1572214571Sdim entry.gotidx = -1; 1573214571Sdim 1574214571Sdim memcpy (*loc, &entry, sizeof (entry)); 1575214571Sdim 1576214571Sdim if (h->got.offset != MINUS_ONE) 1577214571Sdim return TRUE; 1578214571Sdim 1579214571Sdim /* By setting this to a value other than -1, we are indicating that 1580214571Sdim there needs to be a GOT entry for H. Avoid using zero, as the 1581214571Sdim generic ELF copy_indirect_symbol tests for <= 0. */ 1582214571Sdim h->got.offset = 1; 1583214571Sdim 1584214571Sdim return TRUE; 1585214571Sdim} 1586214571Sdim 1587214571Sdim/* Reserve space in G for a GOT entry containing the value of symbol 1588214571Sdim SYMNDX in input bfd ABDF, plus ADDEND. */ 1589214571Sdim 1590214571Sdimstatic bfd_boolean 1591214571Sdimscore_elf_record_local_got_symbol (bfd *abfd, 1592214571Sdim long symndx, 1593214571Sdim bfd_vma addend, 1594214571Sdim struct score_got_info *g) 1595214571Sdim{ 1596214571Sdim struct score_got_entry entry, **loc; 1597214571Sdim 1598214571Sdim entry.abfd = abfd; 1599214571Sdim entry.symndx = symndx; 1600214571Sdim entry.d.addend = addend; 1601214571Sdim loc = (struct score_got_entry **)htab_find_slot (g->got_entries, &entry, INSERT); 1602214571Sdim 1603214571Sdim if (*loc) 1604214571Sdim return TRUE; 1605214571Sdim 1606214571Sdim entry.gotidx = g->local_gotno++; 1607214571Sdim 1608214571Sdim *loc = bfd_alloc (abfd, sizeof(entry)); 1609214571Sdim if (! *loc) 1610214571Sdim return FALSE; 1611214571Sdim 1612214571Sdim memcpy (*loc, &entry, sizeof (entry)); 1613214571Sdim 1614214571Sdim return TRUE; 1615214571Sdim} 1616214571Sdim 1617214571Sdim/* Returns the GOT offset at which the indicated address can be found. 1618214571Sdim If there is not yet a GOT entry for this value, create one. 1619214571Sdim Returns -1 if no satisfactory GOT offset can be found. */ 1620214571Sdim 1621214571Sdimstatic bfd_vma 1622214571Sdimscore_elf_local_got_index (bfd *abfd, bfd *ibfd, struct bfd_link_info *info, 1623214571Sdim bfd_vma value, unsigned long r_symndx, 1624214571Sdim struct score_elf_link_hash_entry *h, int r_type) 1625214571Sdim{ 1626214571Sdim asection *sgot; 1627214571Sdim struct score_got_info *g; 1628214571Sdim struct score_got_entry *entry; 1629214571Sdim 1630214571Sdim g = score_elf_got_info (elf_hash_table (info)->dynobj, &sgot); 1631214571Sdim 1632214571Sdim entry = score_elf_create_local_got_entry (abfd, ibfd, g, sgot, value, 1633214571Sdim r_symndx, h, r_type); 1634214571Sdim if (!entry) 1635214571Sdim return MINUS_ONE; 1636214571Sdim 1637214571Sdim else 1638214571Sdim return entry->gotidx; 1639214571Sdim} 1640214571Sdim 1641214571Sdim/* Returns the GOT index for the global symbol indicated by H. */ 1642214571Sdim 1643214571Sdimstatic bfd_vma 1644214571Sdimscore_elf_global_got_index (bfd *abfd, struct elf_link_hash_entry *h) 1645214571Sdim{ 1646214571Sdim bfd_vma index; 1647214571Sdim asection *sgot; 1648214571Sdim struct score_got_info *g; 1649214571Sdim long global_got_dynindx = 0; 1650214571Sdim 1651214571Sdim g = score_elf_got_info (abfd, &sgot); 1652214571Sdim if (g->global_gotsym != NULL) 1653214571Sdim global_got_dynindx = g->global_gotsym->dynindx; 1654214571Sdim 1655214571Sdim /* Once we determine the global GOT entry with the lowest dynamic 1656214571Sdim symbol table index, we must put all dynamic symbols with greater 1657214571Sdim indices into the GOT. That makes it easy to calculate the GOT 1658214571Sdim offset. */ 1659214571Sdim BFD_ASSERT (h->dynindx >= global_got_dynindx); 1660214571Sdim index = ((h->dynindx - global_got_dynindx + g->local_gotno) * SCORE_ELF_GOT_SIZE (abfd)); 1661214571Sdim BFD_ASSERT (index < sgot->size); 1662214571Sdim 1663214571Sdim return index; 1664214571Sdim} 1665214571Sdim 1666214571Sdim/* Returns the offset for the entry at the INDEXth position in the GOT. */ 1667214571Sdim 1668214571Sdimstatic bfd_vma 1669214571Sdimscore_elf_got_offset_from_index (bfd *dynobj, bfd *output_bfd, 1670214571Sdim bfd *input_bfd ATTRIBUTE_UNUSED, bfd_vma index) 1671214571Sdim{ 1672214571Sdim asection *sgot; 1673214571Sdim bfd_vma gp; 1674214571Sdim struct score_got_info *g; 1675214571Sdim 1676214571Sdim g = score_elf_got_info (dynobj, &sgot); 1677214571Sdim gp = _bfd_get_gp_value (output_bfd); 1678214571Sdim 1679214571Sdim return sgot->output_section->vma + sgot->output_offset + index - gp; 1680214571Sdim} 1681214571Sdim 1682214571Sdim/* Follow indirect and warning hash entries so that each got entry 1683214571Sdim points to the final symbol definition. P must point to a pointer 1684214571Sdim to the hash table we're traversing. Since this traversal may 1685214571Sdim modify the hash table, we set this pointer to NULL to indicate 1686214571Sdim we've made a potentially-destructive change to the hash table, so 1687214571Sdim the traversal must be restarted. */ 1688214571Sdimstatic int 1689214571Sdimscore_elf_resolve_final_got_entry (void **entryp, void *p) 1690214571Sdim{ 1691214571Sdim struct score_got_entry *entry = (struct score_got_entry *)*entryp; 1692214571Sdim htab_t got_entries = *(htab_t *)p; 1693214571Sdim 1694214571Sdim if (entry->abfd != NULL && entry->symndx == -1) 1695214571Sdim { 1696214571Sdim struct score_elf_link_hash_entry *h = entry->d.h; 1697214571Sdim 1698214571Sdim while (h->root.root.type == bfd_link_hash_indirect 1699214571Sdim || h->root.root.type == bfd_link_hash_warning) 1700214571Sdim h = (struct score_elf_link_hash_entry *) h->root.root.u.i.link; 1701214571Sdim 1702214571Sdim if (entry->d.h == h) 1703214571Sdim return 1; 1704214571Sdim 1705214571Sdim entry->d.h = h; 1706214571Sdim 1707214571Sdim /* If we can't find this entry with the new bfd hash, re-insert 1708214571Sdim it, and get the traversal restarted. */ 1709214571Sdim if (! htab_find (got_entries, entry)) 1710214571Sdim { 1711214571Sdim htab_clear_slot (got_entries, entryp); 1712214571Sdim entryp = htab_find_slot (got_entries, entry, INSERT); 1713214571Sdim if (! *entryp) 1714214571Sdim *entryp = entry; 1715214571Sdim /* Abort the traversal, since the whole table may have 1716214571Sdim moved, and leave it up to the parent to restart the 1717214571Sdim process. */ 1718214571Sdim *(htab_t *)p = NULL; 1719214571Sdim return 0; 1720214571Sdim } 1721214571Sdim /* We might want to decrement the global_gotno count, but it's 1722214571Sdim either too early or too late for that at this point. */ 1723214571Sdim } 1724214571Sdim 1725214571Sdim return 1; 1726214571Sdim} 1727214571Sdim 1728214571Sdim/* Turn indirect got entries in a got_entries table into their final locations. */ 1729214571Sdimstatic void 1730214571Sdimscore_elf_resolve_final_got_entries (struct score_got_info *g) 1731214571Sdim{ 1732214571Sdim htab_t got_entries; 1733214571Sdim 1734214571Sdim do 1735214571Sdim { 1736214571Sdim got_entries = g->got_entries; 1737214571Sdim 1738214571Sdim htab_traverse (got_entries, 1739214571Sdim score_elf_resolve_final_got_entry, 1740214571Sdim &got_entries); 1741214571Sdim } 1742214571Sdim while (got_entries == NULL); 1743214571Sdim} 1744214571Sdim 1745214571Sdim/* Add INCREMENT to the reloc (of type HOWTO) at ADDRESS. for -r */ 1746214571Sdim 1747214571Sdimstatic void 1748214571Sdimscore_elf_add_to_rel (bfd *abfd, 1749214571Sdim bfd_byte *address, 1750214571Sdim reloc_howto_type *howto, 1751214571Sdim bfd_signed_vma increment) 1752214571Sdim{ 1753214571Sdim bfd_signed_vma addend; 1754214571Sdim bfd_vma contents; 1755214571Sdim unsigned long offset; 1756214571Sdim unsigned long r_type = howto->type; 1757214571Sdim unsigned long hi16_addend, hi16_offset, hi16_value, uvalue; 1758214571Sdim 1759214571Sdim contents = bfd_get_32 (abfd, address); 1760214571Sdim /* Get the (signed) value from the instruction. */ 1761214571Sdim addend = contents & howto->src_mask; 1762214571Sdim if (addend & ((howto->src_mask + 1) >> 1)) 1763214571Sdim { 1764214571Sdim bfd_signed_vma mask; 1765214571Sdim 1766214571Sdim mask = -1; 1767214571Sdim mask &= ~howto->src_mask; 1768214571Sdim addend |= mask; 1769214571Sdim } 1770214571Sdim /* Add in the increment, (which is a byte value). */ 1771214571Sdim switch (r_type) 1772214571Sdim { 1773214571Sdim case R_SCORE_PC19: 1774214571Sdim offset = 1775214571Sdim (((contents & howto->src_mask) & 0x3ff0000) >> 6) | ((contents & howto->src_mask) & 0x3ff); 1776214571Sdim offset += increment; 1777214571Sdim contents = 1778214571Sdim (contents & ~howto-> 1779214571Sdim src_mask) | (((offset << 6) & howto->src_mask) & 0x3ff0000) | (offset & 0x3ff); 1780214571Sdim bfd_put_32 (abfd, contents, address); 1781214571Sdim break; 1782214571Sdim case R_SCORE_HI16: 1783214571Sdim break; 1784214571Sdim case R_SCORE_LO16: 1785214571Sdim hi16_addend = bfd_get_32 (abfd, address - 4); 1786214571Sdim hi16_offset = ((((hi16_addend >> 16) & 0x3) << 15) | (hi16_addend & 0x7fff)) >> 1; 1787214571Sdim offset = ((((contents >> 16) & 0x3) << 15) | (contents & 0x7fff)) >> 1; 1788214571Sdim offset = (hi16_offset << 16) | (offset & 0xffff); 1789214571Sdim uvalue = increment + offset; 1790214571Sdim hi16_offset = (uvalue >> 16) << 1; 1791214571Sdim hi16_value = (hi16_addend & (~(howto->dst_mask))) 1792214571Sdim | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000); 1793214571Sdim bfd_put_32 (abfd, hi16_value, address - 4); 1794214571Sdim offset = (uvalue & 0xffff) << 1; 1795214571Sdim contents = (contents & (~(howto->dst_mask))) | (offset & 0x7fff) | ((offset << 1) & 0x30000); 1796214571Sdim bfd_put_32 (abfd, contents, address); 1797214571Sdim break; 1798214571Sdim case R_SCORE_24: 1799214571Sdim offset = 1800214571Sdim (((contents & howto->src_mask) >> 1) & 0x1ff8000) | ((contents & howto->src_mask) & 0x7fff); 1801214571Sdim offset += increment; 1802214571Sdim contents = 1803214571Sdim (contents & ~howto-> 1804214571Sdim src_mask) | (((offset << 1) & howto->src_mask) & 0x3ff0000) | (offset & 0x7fff); 1805214571Sdim bfd_put_32 (abfd, contents, address); 1806214571Sdim break; 1807214571Sdim case R_SCORE16_11: 1808214571Sdim 1809214571Sdim contents = bfd_get_16 (abfd, address); 1810214571Sdim offset = contents & howto->src_mask; 1811214571Sdim offset += increment; 1812214571Sdim contents = (contents & ~howto->src_mask) | (offset & howto->src_mask); 1813214571Sdim bfd_put_16 (abfd, contents, address); 1814214571Sdim 1815214571Sdim break; 1816214571Sdim case R_SCORE16_PC8: 1817214571Sdim 1818214571Sdim contents = bfd_get_16 (abfd, address); 1819214571Sdim offset = (contents & howto->src_mask) + ((increment >> 1) & 0xff); 1820214571Sdim contents = (contents & (~howto->src_mask)) | (offset & howto->src_mask); 1821214571Sdim bfd_put_16 (abfd, contents, address); 1822214571Sdim 1823214571Sdim break; 1824214571Sdim default: 1825214571Sdim addend += increment; 1826214571Sdim contents = (contents & ~howto->dst_mask) | (addend & howto->dst_mask); 1827214571Sdim bfd_put_32 (abfd, contents, address); 1828214571Sdim break; 1829214571Sdim } 1830214571Sdim} 1831214571Sdim 1832214571Sdim/* Perform a relocation as part of a final link. */ 1833214571Sdim 1834214571Sdimstatic bfd_reloc_status_type 1835214571Sdimscore_elf_final_link_relocate (reloc_howto_type *howto, 1836214571Sdim bfd *input_bfd, 1837214571Sdim bfd *output_bfd, 1838214571Sdim asection *input_section, 1839214571Sdim bfd_byte *contents, 1840214571Sdim Elf_Internal_Rela *rel, 1841214571Sdim Elf_Internal_Rela *relocs, 1842214571Sdim bfd_vma symbol, 1843214571Sdim struct bfd_link_info *info, 1844214571Sdim const char *sym_name ATTRIBUTE_UNUSED, 1845214571Sdim int sym_flags ATTRIBUTE_UNUSED, 1846214571Sdim struct score_elf_link_hash_entry *h, 1847214571Sdim asection **local_sections, 1848214571Sdim bfd_boolean gp_disp_p) 1849214571Sdim{ 1850214571Sdim unsigned long r_type; 1851214571Sdim unsigned long r_symndx; 1852214571Sdim bfd_byte *hit_data = contents + rel->r_offset; 1853214571Sdim bfd_vma addend; 1854214571Sdim /* The final GP value to be used for the relocatable, executable, or 1855214571Sdim shared object file being produced. */ 1856214571Sdim bfd_vma gp = MINUS_ONE; 1857214571Sdim /* The place (section offset or address) of the storage unit being relocated. */ 1858214571Sdim bfd_vma rel_addr; 1859214571Sdim /* The value of GP used to create the relocatable object. */ 1860214571Sdim bfd_vma gp0 = MINUS_ONE; 1861214571Sdim /* The offset into the global offset table at which the address of the relocation entry 1862214571Sdim symbol, adjusted by the addend, resides during execution. */ 1863214571Sdim bfd_vma g = MINUS_ONE; 1864214571Sdim /* TRUE if the symbol referred to by this relocation is a local symbol. */ 1865214571Sdim bfd_boolean local_p; 1866214571Sdim /* The eventual value we will relocate. */ 1867214571Sdim bfd_vma value = symbol; 1868214571Sdim unsigned long hi16_addend, hi16_offset, hi16_value, uvalue, offset, abs_value = 0; 1869214571Sdim 1870214571Sdim if (elf_gp (output_bfd) == 0) 1871214571Sdim { 1872214571Sdim struct bfd_link_hash_entry *bh; 1873214571Sdim asection *o; 1874214571Sdim 1875214571Sdim bh = bfd_link_hash_lookup (info->hash, "_gp", 0, 0, 1); 1876214571Sdim if (bh != (struct bfd_link_hash_entry *)NULL && bh->type == bfd_link_hash_defined) 1877214571Sdim elf_gp (output_bfd) = (bh->u.def.value 1878214571Sdim + bh->u.def.section->output_section->vma 1879214571Sdim + bh->u.def.section->output_offset); 1880214571Sdim else if (info->relocatable) 1881214571Sdim { 1882214571Sdim bfd_vma lo = -1; 1883214571Sdim 1884214571Sdim /* Find the GP-relative section with the lowest offset. */ 1885214571Sdim for (o = output_bfd->sections; o != (asection *) NULL; o = o->next) 1886214571Sdim if (o->vma < lo) 1887214571Sdim lo = o->vma; 1888214571Sdim /* And calculate GP relative to that. */ 1889214571Sdim elf_gp (output_bfd) = lo + ELF_SCORE_GP_OFFSET (input_bfd); 1890214571Sdim } 1891214571Sdim else 1892214571Sdim { 1893214571Sdim /* If the relocate_section function needs to do a reloc 1894214571Sdim involving the GP value, it should make a reloc_dangerous 1895214571Sdim callback to warn that GP is not defined. */ 1896214571Sdim } 1897214571Sdim } 1898214571Sdim 1899214571Sdim /* Parse the relocation. */ 1900214571Sdim r_symndx = ELF32_R_SYM (rel->r_info); 1901214571Sdim r_type = ELF32_R_TYPE (rel->r_info); 1902214571Sdim rel_addr = (input_section->output_section->vma + input_section->output_offset + rel->r_offset); 1903214571Sdim local_p = score_elf_local_relocation_p (input_bfd, rel, local_sections, TRUE); 1904214571Sdim 1905214571Sdim if (r_type == R_SCORE_GOT15) 1906214571Sdim { 1907214571Sdim const Elf_Internal_Rela *relend; 1908214571Sdim const Elf_Internal_Rela *lo16_rel; 1909214571Sdim const struct elf_backend_data *bed; 1910214571Sdim bfd_vma lo_value = 0; 1911214571Sdim 1912214571Sdim bed = get_elf_backend_data (output_bfd); 1913214571Sdim relend = relocs + input_section->reloc_count * bed->s->int_rels_per_ext_rel; 1914214571Sdim lo16_rel = score_elf_next_relocation (input_bfd, R_SCORE_GOT_LO16, rel, relend); 1915214571Sdim if ((local_p) && (lo16_rel != NULL)) 1916214571Sdim { 1917214571Sdim bfd_vma tmp = 0; 1918214571Sdim tmp = bfd_get_32 (input_bfd, contents + lo16_rel->r_offset); 1919214571Sdim lo_value = (((tmp >> 16) & 0x3) << 14) | ((tmp & 0x7fff) >> 1); 1920214571Sdim } 1921214571Sdim addend = lo_value; 1922214571Sdim } 1923214571Sdim else 1924214571Sdim { 1925214571Sdim addend = (bfd_get_32 (input_bfd, hit_data) >> howto->bitpos) & howto->src_mask; 1926214571Sdim } 1927214571Sdim 1928214571Sdim /* If we haven't already determined the GOT offset, or the GP value, 1929214571Sdim and we're going to need it, get it now. */ 1930214571Sdim switch (r_type) 1931214571Sdim { 1932214571Sdim case R_SCORE_CALL15: 1933214571Sdim case R_SCORE_GOT15: 1934214571Sdim if (!local_p) 1935214571Sdim { 1936214571Sdim g = score_elf_global_got_index (elf_hash_table (info)->dynobj, 1937214571Sdim (struct elf_link_hash_entry *) h); 1938214571Sdim if ((! elf_hash_table(info)->dynamic_sections_created 1939214571Sdim || (info->shared 1940214571Sdim && (info->symbolic || h->root.dynindx == -1) 1941214571Sdim && h->root.def_regular))) 1942214571Sdim { 1943214571Sdim /* This is a static link or a -Bsymbolic link. The 1944214571Sdim symbol is defined locally, or was forced to be local. 1945214571Sdim We must initialize this entry in the GOT. */ 1946214571Sdim bfd *tmpbfd = elf_hash_table (info)->dynobj; 1947214571Sdim asection *sgot = score_elf_got_section (tmpbfd, FALSE); 1948214571Sdim bfd_put_32 (tmpbfd, value, sgot->contents + g); 1949214571Sdim } 1950214571Sdim } 1951214571Sdim else if (r_type == R_SCORE_GOT15 || r_type == R_SCORE_CALL15) 1952214571Sdim { 1953214571Sdim /* There's no need to create a local GOT entry here; the 1954214571Sdim calculation for a local GOT15 entry does not involve G. */ 1955214571Sdim ; 1956214571Sdim } 1957214571Sdim else 1958214571Sdim { 1959214571Sdim g = score_elf_local_got_index (output_bfd, input_bfd, info, 1960214571Sdim symbol + addend, r_symndx, h, r_type); 1961214571Sdim if (g == MINUS_ONE) 1962214571Sdim return bfd_reloc_outofrange; 1963214571Sdim } 1964214571Sdim 1965214571Sdim /* Convert GOT indices to actual offsets. */ 1966214571Sdim g = score_elf_got_offset_from_index (elf_hash_table (info)->dynobj, 1967214571Sdim output_bfd, input_bfd, g); 1968214571Sdim break; 1969214571Sdim 1970214571Sdim case R_SCORE_HI16: 1971214571Sdim case R_SCORE_LO16: 1972214571Sdim case R_SCORE_GPREL32: 1973214571Sdim gp0 = _bfd_get_gp_value (input_bfd); 1974214571Sdim gp = _bfd_get_gp_value (output_bfd); 1975214571Sdim break; 1976214571Sdim 1977214571Sdim case R_SCORE_GP15: 1978214571Sdim gp = _bfd_get_gp_value (output_bfd); 1979214571Sdim 1980214571Sdim default: 1981214571Sdim break; 1982214571Sdim } 1983214571Sdim 1984214571Sdim switch (r_type) 1985214571Sdim { 1986214571Sdim case R_SCORE_NONE: 1987214571Sdim return bfd_reloc_ok; 1988214571Sdim 1989214571Sdim case R_SCORE_ABS32: 1990214571Sdim case R_SCORE_REL32: 1991214571Sdim if ((info->shared 1992214571Sdim || (elf_hash_table (info)->dynamic_sections_created 1993214571Sdim && h != NULL 1994214571Sdim && h->root.def_dynamic 1995214571Sdim && !h->root.def_regular)) 1996214571Sdim && r_symndx != 0 1997214571Sdim && (input_section->flags & SEC_ALLOC) != 0) 1998214571Sdim { 1999214571Sdim /* If we're creating a shared library, or this relocation is against a symbol 2000214571Sdim in a shared library, then we can't know where the symbol will end up. 2001214571Sdim So, we create a relocation record in the output, and leave the job up 2002214571Sdim to the dynamic linker. */ 2003214571Sdim value = addend; 2004214571Sdim if (!score_elf_create_dynamic_relocation (output_bfd, info, rel, h, 2005214571Sdim symbol, &value, 2006214571Sdim input_section)) 2007214571Sdim return bfd_reloc_undefined; 2008214571Sdim } 2009214571Sdim else 2010214571Sdim { 2011214571Sdim if (r_type != R_SCORE_REL32) 2012214571Sdim value = symbol + addend; 2013214571Sdim else 2014214571Sdim value = addend; 2015214571Sdim } 2016214571Sdim value &= howto->dst_mask; 2017214571Sdim bfd_put_32 (input_bfd, value, hit_data); 2018214571Sdim return bfd_reloc_ok; 2019214571Sdim 2020214571Sdim case R_SCORE_ABS16: 2021214571Sdim value += addend; 2022214571Sdim if ((long)value > 0x7fff || (long)value < -0x8000) 2023214571Sdim return bfd_reloc_overflow; 2024214571Sdim bfd_put_16 (input_bfd, value, hit_data); 2025214571Sdim return bfd_reloc_ok; 2026214571Sdim 2027214571Sdim case R_SCORE_24: 2028214571Sdim addend = bfd_get_32 (input_bfd, hit_data); 2029214571Sdim offset = (((addend & howto->src_mask) >> 1) & 0x1ff8000) | ((addend & howto->src_mask) & 0x7fff); 2030214571Sdim if ((offset & 0x1000000) != 0) 2031214571Sdim offset |= 0xfe000000; 2032214571Sdim value += offset; 2033214571Sdim addend = (addend & ~howto->src_mask) 2034214571Sdim | (((value << 1) & howto->src_mask) & 0x3ff0000) | (value & 0x7fff); 2035214571Sdim bfd_put_32 (input_bfd, addend, hit_data); 2036214571Sdim return bfd_reloc_ok; 2037214571Sdim 2038214571Sdim case R_SCORE_PC19: 2039214571Sdim addend = bfd_get_32 (input_bfd, hit_data); 2040214571Sdim offset = (((addend & howto->src_mask) & 0x3ff0000) >> 6) | ((addend & howto->src_mask) & 0x3ff); 2041214571Sdim if ((offset & 0x80000) != 0) 2042214571Sdim offset |= 0xfff00000; 2043214571Sdim abs_value = value = value - rel_addr + offset; 2044214571Sdim /* exceed 20 bit : overflow. */ 2045214571Sdim if ((abs_value & 0x80000000) == 0x80000000) 2046214571Sdim abs_value = 0xffffffff - value + 1; 2047214571Sdim if ((abs_value & 0xfff80000) != 0) 2048214571Sdim return bfd_reloc_overflow; 2049214571Sdim addend = (addend & ~howto->src_mask) 2050214571Sdim | (((value << 6) & howto->src_mask) & 0x3ff0000) | (value & 0x3ff); 2051214571Sdim bfd_put_32 (input_bfd, addend, hit_data); 2052214571Sdim return bfd_reloc_ok; 2053214571Sdim 2054214571Sdim case R_SCORE16_11: 2055214571Sdim addend = bfd_get_16 (input_bfd, hit_data); 2056214571Sdim offset = addend & howto->src_mask; 2057214571Sdim if ((offset & 0x800) != 0) /* Offset is negative. */ 2058214571Sdim offset |= 0xfffff000; 2059214571Sdim value += offset; 2060214571Sdim addend = (addend & ~howto->src_mask) | (value & howto->src_mask); 2061214571Sdim bfd_put_16 (input_bfd, addend, hit_data); 2062214571Sdim return bfd_reloc_ok; 2063214571Sdim 2064214571Sdim case R_SCORE16_PC8: 2065214571Sdim addend = bfd_get_16 (input_bfd, hit_data); 2066214571Sdim offset = (addend & howto->src_mask) << 1; 2067214571Sdim if ((offset & 0x100) != 0) /* Offset is negative. */ 2068214571Sdim offset |= 0xfffffe00; 2069214571Sdim abs_value = value = value - rel_addr + offset; 2070214571Sdim /* Sign bit + exceed 9 bit. */ 2071214571Sdim if (((value & 0xffffff00) != 0) && ((value & 0xffffff00) != 0xffffff00)) 2072214571Sdim return bfd_reloc_overflow; 2073214571Sdim value >>= 1; 2074214571Sdim addend = (addend & ~howto->src_mask) | (value & howto->src_mask); 2075214571Sdim bfd_put_16 (input_bfd, addend, hit_data); 2076214571Sdim return bfd_reloc_ok; 2077214571Sdim 2078214571Sdim case R_SCORE_HI16: 2079214571Sdim return bfd_reloc_ok; 2080214571Sdim 2081214571Sdim case R_SCORE_LO16: 2082214571Sdim hi16_addend = bfd_get_32 (input_bfd, hit_data - 4); 2083214571Sdim hi16_offset = ((((hi16_addend >> 16) & 0x3) << 15) | (hi16_addend & 0x7fff)) >> 1; 2084214571Sdim addend = bfd_get_32 (input_bfd, hit_data); 2085214571Sdim offset = ((((addend >> 16) & 0x3) << 15) | (addend & 0x7fff)) >> 1; 2086214571Sdim offset = (hi16_offset << 16) | (offset & 0xffff); 2087214571Sdim 2088214571Sdim if (!gp_disp_p) 2089214571Sdim uvalue = value + offset; 2090214571Sdim else 2091214571Sdim uvalue = offset + gp - rel_addr + 4; 2092214571Sdim 2093214571Sdim hi16_offset = (uvalue >> 16) << 1; 2094214571Sdim hi16_value = (hi16_addend & (~(howto->dst_mask))) 2095214571Sdim | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000); 2096214571Sdim bfd_put_32 (input_bfd, hi16_value, hit_data - 4); 2097214571Sdim offset = (uvalue & 0xffff) << 1; 2098214571Sdim value = (addend & (~(howto->dst_mask))) | (offset & 0x7fff) | ((offset << 1) & 0x30000); 2099214571Sdim bfd_put_32 (input_bfd, value, hit_data); 2100214571Sdim return bfd_reloc_ok; 2101214571Sdim 2102214571Sdim case R_SCORE_GP15: 2103214571Sdim addend = bfd_get_32 (input_bfd, hit_data); 2104214571Sdim offset = addend & 0x7fff; 2105214571Sdim if ((offset & 0x4000) == 0x4000) 2106214571Sdim offset |= 0xffffc000; 2107214571Sdim value = value + offset - gp; 2108214571Sdim if (((value & 0xffffc000) != 0) && ((value & 0xffffc000) != 0xffffc000)) 2109214571Sdim return bfd_reloc_overflow; 2110214571Sdim value = (addend & ~howto->src_mask) | (value & howto->src_mask); 2111214571Sdim bfd_put_32 (input_bfd, value, hit_data); 2112214571Sdim return bfd_reloc_ok; 2113214571Sdim 2114214571Sdim case R_SCORE_GOT15: 2115214571Sdim case R_SCORE_CALL15: 2116214571Sdim if (local_p) 2117214571Sdim { 2118214571Sdim bfd_boolean forced; 2119214571Sdim 2120214571Sdim /* The special case is when the symbol is forced to be local. We need the 2121214571Sdim full address in the GOT since no R_SCORE_GOT_LO16 relocation follows. */ 2122214571Sdim forced = ! score_elf_local_relocation_p (input_bfd, rel, 2123214571Sdim local_sections, FALSE); 2124214571Sdim value = score_elf_got16_entry (output_bfd, input_bfd, info, 2125214571Sdim symbol + addend, forced); 2126214571Sdim if (value == MINUS_ONE) 2127214571Sdim return bfd_reloc_outofrange; 2128214571Sdim value = score_elf_got_offset_from_index (elf_hash_table (info)->dynobj, 2129214571Sdim output_bfd, input_bfd, value); 2130214571Sdim } 2131214571Sdim else 2132214571Sdim { 2133214571Sdim value = g; 2134214571Sdim } 2135214571Sdim 2136214571Sdim if ((long) value > 0x3fff || (long) value < -0x4000) 2137214571Sdim return bfd_reloc_overflow; 2138214571Sdim 2139214571Sdim addend = bfd_get_32 (input_bfd, hit_data); 2140214571Sdim value = (addend & ~howto->dst_mask) | (value & howto->dst_mask); 2141214571Sdim bfd_put_32 (input_bfd, value, hit_data); 2142214571Sdim return bfd_reloc_ok; 2143214571Sdim 2144214571Sdim case R_SCORE_GPREL32: 2145214571Sdim value = (addend + symbol - gp); 2146214571Sdim value &= howto->dst_mask; 2147214571Sdim bfd_put_32 (input_bfd, value, hit_data); 2148214571Sdim return bfd_reloc_ok; 2149214571Sdim 2150214571Sdim case R_SCORE_GOT_LO16: 2151214571Sdim addend = bfd_get_32 (input_bfd, hit_data); 2152214571Sdim value = (((addend >> 16) & 0x3) << 14) | ((addend & 0x7fff) >> 1); 2153214571Sdim value += symbol; 2154214571Sdim value = (addend & (~(howto->dst_mask))) | ((value & 0x3fff) << 1) 2155214571Sdim | (((value >> 14) & 0x3) << 16); 2156214571Sdim 2157214571Sdim bfd_put_32 (input_bfd, value, hit_data); 2158214571Sdim return bfd_reloc_ok; 2159214571Sdim 2160214571Sdim case R_SCORE_DUMMY_HI16: 2161214571Sdim return bfd_reloc_ok; 2162214571Sdim 2163214571Sdim case R_SCORE_GNU_VTINHERIT: 2164214571Sdim case R_SCORE_GNU_VTENTRY: 2165214571Sdim /* We don't do anything with these at present. */ 2166214571Sdim return bfd_reloc_continue; 2167214571Sdim 2168214571Sdim default: 2169214571Sdim return bfd_reloc_notsupported; 2170214571Sdim } 2171214571Sdim} 2172214571Sdim 2173214571Sdim/* Score backend functions. */ 2174214571Sdim 2175214571Sdimstatic void 2176214571Sdim_bfd_score_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, 2177214571Sdim arelent *bfd_reloc, 2178214571Sdim Elf_Internal_Rela *elf_reloc) 2179214571Sdim{ 2180214571Sdim unsigned int r_type; 2181214571Sdim 2182214571Sdim r_type = ELF32_R_TYPE (elf_reloc->r_info); 2183214571Sdim if (r_type >= NUM_ELEM (elf32_score_howto_table)) 2184214571Sdim bfd_reloc->howto = NULL; 2185214571Sdim else 2186214571Sdim bfd_reloc->howto = &elf32_score_howto_table[r_type]; 2187214571Sdim} 2188214571Sdim 2189214571Sdim/* Relocate an score ELF section. */ 2190214571Sdim 2191214571Sdimstatic bfd_boolean 2192214571Sdim_bfd_score_elf_relocate_section (bfd *output_bfd, 2193214571Sdim struct bfd_link_info *info, 2194214571Sdim bfd *input_bfd, 2195214571Sdim asection *input_section, 2196214571Sdim bfd_byte *contents, 2197214571Sdim Elf_Internal_Rela *relocs, 2198214571Sdim Elf_Internal_Sym *local_syms, 2199214571Sdim asection **local_sections) 2200214571Sdim{ 2201214571Sdim Elf_Internal_Shdr *symtab_hdr; 2202214571Sdim struct elf_link_hash_entry **sym_hashes; 2203214571Sdim Elf_Internal_Rela *rel; 2204214571Sdim Elf_Internal_Rela *relend; 2205214571Sdim const char *name; 2206214571Sdim unsigned long offset; 2207214571Sdim unsigned long hi16_addend, hi16_offset, hi16_value, uvalue; 2208214571Sdim size_t extsymoff; 2209214571Sdim bfd_boolean gp_disp_p = FALSE; 2210214571Sdim 2211214571Sdim /* Sort dynsym. */ 2212214571Sdim if (elf_hash_table (info)->dynamic_sections_created) 2213214571Sdim { 2214214571Sdim bfd_size_type dynsecsymcount = 0; 2215214571Sdim if (info->shared) 2216214571Sdim { 2217214571Sdim asection * p; 2218214571Sdim const struct elf_backend_data *bed = get_elf_backend_data (output_bfd); 2219214571Sdim 2220214571Sdim for (p = output_bfd->sections; p ; p = p->next) 2221214571Sdim if ((p->flags & SEC_EXCLUDE) == 0 2222214571Sdim && (p->flags & SEC_ALLOC) != 0 2223214571Sdim && !(*bed->elf_backend_omit_section_dynsym) (output_bfd, info, p)) 2224214571Sdim ++ dynsecsymcount; 2225214571Sdim } 2226214571Sdim 2227214571Sdim if (!score_elf_sort_hash_table (info, dynsecsymcount + 1)) 2228214571Sdim return FALSE; 2229214571Sdim } 2230214571Sdim 2231214571Sdim symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; 2232214571Sdim extsymoff = (elf_bad_symtab (input_bfd)) ? 0 : symtab_hdr->sh_info; 2233214571Sdim sym_hashes = elf_sym_hashes (input_bfd); 2234214571Sdim rel = relocs; 2235214571Sdim relend = relocs + input_section->reloc_count; 2236214571Sdim for (; rel < relend; rel++) 2237214571Sdim { 2238214571Sdim int r_type; 2239214571Sdim reloc_howto_type *howto; 2240214571Sdim unsigned long r_symndx; 2241214571Sdim Elf_Internal_Sym *sym; 2242214571Sdim asection *sec; 2243214571Sdim struct score_elf_link_hash_entry *h; 2244214571Sdim bfd_vma relocation = 0; 2245214571Sdim bfd_reloc_status_type r; 2246214571Sdim arelent bfd_reloc; 2247214571Sdim 2248214571Sdim r_symndx = ELF32_R_SYM (rel->r_info); 2249214571Sdim r_type = ELF32_R_TYPE (rel->r_info); 2250214571Sdim 2251214571Sdim _bfd_score_info_to_howto (input_bfd, &bfd_reloc, (Elf_Internal_Rela *) rel); 2252214571Sdim howto = bfd_reloc.howto; 2253214571Sdim 2254214571Sdim h = NULL; 2255214571Sdim sym = NULL; 2256214571Sdim sec = NULL; 2257214571Sdim 2258214571Sdim if (r_symndx < extsymoff) 2259214571Sdim { 2260214571Sdim sym = local_syms + r_symndx; 2261214571Sdim sec = local_sections[r_symndx]; 2262214571Sdim relocation = (sec->output_section->vma 2263214571Sdim + sec->output_offset 2264214571Sdim + sym->st_value); 2265214571Sdim name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, sec); 2266214571Sdim 2267214571Sdim if (!info->relocatable 2268214571Sdim && (sec->flags & SEC_MERGE) != 0 2269214571Sdim && ELF_ST_TYPE (sym->st_info) == STT_SECTION) 2270214571Sdim { 2271214571Sdim asection *msec; 2272214571Sdim bfd_vma addend, value; 2273214571Sdim 2274214571Sdim switch (r_type) 2275214571Sdim { 2276214571Sdim case R_SCORE_HI16: 2277214571Sdim break; 2278214571Sdim case R_SCORE_LO16: 2279214571Sdim hi16_addend = bfd_get_32 (input_bfd, contents + rel->r_offset - 4); 2280214571Sdim hi16_offset = ((((hi16_addend >> 16) & 0x3) << 15) | (hi16_addend & 0x7fff)) >> 1; 2281214571Sdim value = bfd_get_32 (input_bfd, contents + rel->r_offset); 2282214571Sdim offset = ((((value >> 16) & 0x3) << 15) | (value & 0x7fff)) >> 1; 2283214571Sdim addend = (hi16_offset << 16) | (offset & 0xffff); 2284214571Sdim msec = sec; 2285214571Sdim addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend); 2286214571Sdim addend -= relocation; 2287214571Sdim addend += msec->output_section->vma + msec->output_offset; 2288214571Sdim uvalue = addend; 2289214571Sdim hi16_offset = (uvalue >> 16) << 1; 2290214571Sdim hi16_value = (hi16_addend & (~(howto->dst_mask))) 2291214571Sdim | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000); 2292214571Sdim bfd_put_32 (input_bfd, hi16_value, contents + rel->r_offset - 4); 2293214571Sdim offset = (uvalue & 0xffff) << 1; 2294214571Sdim value = (value & (~(howto->dst_mask))) 2295214571Sdim | (offset & 0x7fff) | ((offset << 1) & 0x30000); 2296214571Sdim bfd_put_32 (input_bfd, value, contents + rel->r_offset); 2297214571Sdim break; 2298214571Sdim case R_SCORE_GOT_LO16: 2299214571Sdim value = bfd_get_32 (input_bfd, contents + rel->r_offset); 2300214571Sdim addend = (((value >> 16) & 0x3) << 14) | ((value & 0x7fff) >> 1); 2301214571Sdim msec = sec; 2302214571Sdim addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend) - relocation; 2303214571Sdim addend += msec->output_section->vma + msec->output_offset; 2304214571Sdim value = (value & (~(howto->dst_mask))) | ((addend & 0x3fff) << 1) 2305214571Sdim | (((addend >> 14) & 0x3) << 16); 2306214571Sdim 2307214571Sdim bfd_put_32 (input_bfd, value, contents + rel->r_offset); 2308214571Sdim break; 2309214571Sdim default: 2310214571Sdim value = bfd_get_32 (input_bfd, contents + rel->r_offset); 2311214571Sdim /* Get the (signed) value from the instruction. */ 2312214571Sdim addend = value & howto->src_mask; 2313214571Sdim if (addend & ((howto->src_mask + 1) >> 1)) 2314214571Sdim { 2315214571Sdim bfd_signed_vma mask; 2316214571Sdim 2317214571Sdim mask = -1; 2318214571Sdim mask &= ~howto->src_mask; 2319214571Sdim addend |= mask; 2320214571Sdim } 2321214571Sdim msec = sec; 2322214571Sdim addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend) - relocation; 2323214571Sdim addend += msec->output_section->vma + msec->output_offset; 2324214571Sdim value = (value & ~howto->dst_mask) | (addend & howto->dst_mask); 2325214571Sdim bfd_put_32 (input_bfd, value, contents + rel->r_offset); 2326214571Sdim break; 2327214571Sdim } 2328214571Sdim } 2329214571Sdim } 2330214571Sdim else 2331214571Sdim { 2332214571Sdim /* For global symbols we look up the symbol in the hash-table. */ 2333214571Sdim h = ((struct score_elf_link_hash_entry *) 2334214571Sdim elf_sym_hashes (input_bfd) [r_symndx - extsymoff]); 2335214571Sdim /* Find the real hash-table entry for this symbol. */ 2336214571Sdim while (h->root.root.type == bfd_link_hash_indirect 2337214571Sdim || h->root.root.type == bfd_link_hash_warning) 2338214571Sdim h = (struct score_elf_link_hash_entry *) h->root.root.u.i.link; 2339214571Sdim 2340214571Sdim /* Record the name of this symbol, for our caller. */ 2341214571Sdim name = h->root.root.root.string; 2342214571Sdim 2343214571Sdim /* See if this is the special GP_DISP_LABEL symbol. Note that such a 2344214571Sdim symbol must always be a global symbol. */ 2345214571Sdim if (strcmp (name, GP_DISP_LABEL) == 0) 2346214571Sdim { 2347214571Sdim /* Relocations against GP_DISP_LABEL are permitted only with 2348214571Sdim R_SCORE_HI16 and R_SCORE_LO16 relocations. */ 2349214571Sdim if (r_type != R_SCORE_HI16 && r_type != R_SCORE_LO16) 2350214571Sdim return bfd_reloc_notsupported; 2351214571Sdim 2352214571Sdim gp_disp_p = TRUE; 2353214571Sdim } 2354214571Sdim 2355214571Sdim /* If this symbol is defined, calculate its address. Note that 2356214571Sdim GP_DISP_LABEL is a magic symbol, always implicitly defined by the 2357214571Sdim linker, so it's inappropriate to check to see whether or not 2358214571Sdim its defined. */ 2359214571Sdim else if ((h->root.root.type == bfd_link_hash_defined 2360214571Sdim || h->root.root.type == bfd_link_hash_defweak) 2361214571Sdim && h->root.root.u.def.section) 2362214571Sdim { 2363214571Sdim sec = h->root.root.u.def.section; 2364214571Sdim if (sec->output_section) 2365214571Sdim relocation = (h->root.root.u.def.value 2366214571Sdim + sec->output_section->vma 2367214571Sdim + sec->output_offset); 2368214571Sdim else 2369214571Sdim { 2370214571Sdim relocation = h->root.root.u.def.value; 2371214571Sdim } 2372214571Sdim } 2373214571Sdim else if (h->root.root.type == bfd_link_hash_undefweak) 2374214571Sdim /* We allow relocations against undefined weak symbols, giving 2375214571Sdim it the value zero, so that you can undefined weak functions 2376214571Sdim and check to see if they exist by looking at their addresses. */ 2377214571Sdim relocation = 0; 2378214571Sdim else if (info->unresolved_syms_in_objects == RM_IGNORE 2379214571Sdim && ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT) 2380214571Sdim relocation = 0; 2381214571Sdim else if (strcmp (name, "_DYNAMIC_LINK") == 0) 2382214571Sdim { 2383214571Sdim /* If this is a dynamic link, we should have created a _DYNAMIC_LINK symbol 2384214571Sdim in _bfd_score_elf_create_dynamic_sections. Otherwise, we should define 2385214571Sdim the symbol with a value of 0. */ 2386214571Sdim BFD_ASSERT (! info->shared); 2387214571Sdim BFD_ASSERT (bfd_get_section_by_name (output_bfd, ".dynamic") == NULL); 2388214571Sdim relocation = 0; 2389214571Sdim } 2390214571Sdim else if (!info->relocatable) 2391214571Sdim { 2392214571Sdim if (! ((*info->callbacks->undefined_symbol) 2393214571Sdim (info, h->root.root.root.string, input_bfd, 2394214571Sdim input_section, rel->r_offset, 2395214571Sdim (info->unresolved_syms_in_objects == RM_GENERATE_ERROR) 2396214571Sdim || ELF_ST_VISIBILITY (h->root.other)))) 2397214571Sdim return bfd_reloc_undefined; 2398214571Sdim relocation = 0; 2399214571Sdim } 2400214571Sdim } 2401214571Sdim 2402214571Sdim if (sec != NULL && elf_discarded_section (sec)) 2403214571Sdim { 2404214571Sdim /* For relocs against symbols from removed linkonce sections, 2405214571Sdim or sections discarded by a linker script, we just want the 2406214571Sdim section contents zeroed. Avoid any special processing. */ 2407214571Sdim _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset); 2408214571Sdim rel->r_info = 0; 2409214571Sdim rel->r_addend = 0; 2410214571Sdim continue; 2411214571Sdim } 2412214571Sdim 2413214571Sdim if (info->relocatable) 2414214571Sdim { 2415214571Sdim /* This is a relocatable link. We don't have to change 2416214571Sdim anything, unless the reloc is against a section symbol, 2417214571Sdim in which case we have to adjust according to where the 2418214571Sdim section symbol winds up in the output section. */ 2419214571Sdim if (sym != NULL && ELF_ST_TYPE (sym->st_info) == STT_SECTION) 2420214571Sdim score_elf_add_to_rel (input_bfd, contents + rel->r_offset, 2421214571Sdim howto, (bfd_signed_vma) sec->output_offset); 2422214571Sdim continue; 2423214571Sdim } 2424214571Sdim 2425214571Sdim r = score_elf_final_link_relocate (howto, input_bfd, output_bfd, 2426214571Sdim input_section, contents, rel, relocs, 2427214571Sdim relocation, info, name, 2428214571Sdim (h ? ELF_ST_TYPE ((unsigned int)h->root.root.type) : 2429214571Sdim ELF_ST_TYPE ((unsigned int)sym->st_info)), h, local_sections, 2430214571Sdim gp_disp_p); 2431214571Sdim 2432214571Sdim if (r != bfd_reloc_ok) 2433214571Sdim { 2434214571Sdim const char *msg = (const char *)0; 2435214571Sdim 2436214571Sdim switch (r) 2437214571Sdim { 2438214571Sdim case bfd_reloc_overflow: 2439214571Sdim /* If the overflowing reloc was to an undefined symbol, 2440214571Sdim we have already printed one error message and there 2441214571Sdim is no point complaining again. */ 2442214571Sdim if (((!h) || (h->root.root.type != bfd_link_hash_undefined)) 2443214571Sdim && (!((*info->callbacks->reloc_overflow) 2444214571Sdim (info, NULL, name, howto->name, (bfd_vma) 0, 2445214571Sdim input_bfd, input_section, rel->r_offset)))) 2446214571Sdim return FALSE; 2447214571Sdim break; 2448214571Sdim case bfd_reloc_undefined: 2449214571Sdim if (!((*info->callbacks->undefined_symbol) 2450214571Sdim (info, name, input_bfd, input_section, rel->r_offset, TRUE))) 2451214571Sdim return FALSE; 2452214571Sdim break; 2453214571Sdim 2454214571Sdim case bfd_reloc_outofrange: 2455214571Sdim msg = _("internal error: out of range error"); 2456214571Sdim goto common_error; 2457214571Sdim 2458214571Sdim case bfd_reloc_notsupported: 2459214571Sdim msg = _("internal error: unsupported relocation error"); 2460214571Sdim goto common_error; 2461214571Sdim 2462214571Sdim case bfd_reloc_dangerous: 2463214571Sdim msg = _("internal error: dangerous error"); 2464214571Sdim goto common_error; 2465214571Sdim 2466214571Sdim default: 2467214571Sdim msg = _("internal error: unknown error"); 2468214571Sdim /* fall through */ 2469214571Sdim 2470214571Sdim common_error: 2471214571Sdim if (!((*info->callbacks->warning) 2472214571Sdim (info, msg, name, input_bfd, input_section, rel->r_offset))) 2473214571Sdim return FALSE; 2474214571Sdim break; 2475214571Sdim } 2476214571Sdim } 2477214571Sdim } 2478214571Sdim 2479214571Sdim return TRUE; 2480214571Sdim} 2481214571Sdim 2482214571Sdim/* Look through the relocs for a section during the first phase, and 2483214571Sdim allocate space in the global offset table. */ 2484214571Sdim 2485214571Sdimstatic bfd_boolean 2486214571Sdim_bfd_score_elf_check_relocs (bfd *abfd, 2487214571Sdim struct bfd_link_info *info, 2488214571Sdim asection *sec, 2489214571Sdim const Elf_Internal_Rela *relocs) 2490214571Sdim{ 2491214571Sdim const char *name; 2492214571Sdim bfd *dynobj; 2493214571Sdim Elf_Internal_Shdr *symtab_hdr; 2494214571Sdim struct elf_link_hash_entry **sym_hashes; 2495214571Sdim struct score_got_info *g; 2496214571Sdim size_t extsymoff; 2497214571Sdim const Elf_Internal_Rela *rel; 2498214571Sdim const Elf_Internal_Rela *rel_end; 2499214571Sdim asection *sgot; 2500214571Sdim asection *sreloc; 2501214571Sdim const struct elf_backend_data *bed; 2502214571Sdim 2503214571Sdim if (info->relocatable) 2504214571Sdim return TRUE; 2505214571Sdim 2506214571Sdim dynobj = elf_hash_table (info)->dynobj; 2507214571Sdim symtab_hdr = &elf_tdata (abfd)->symtab_hdr; 2508214571Sdim sym_hashes = elf_sym_hashes (abfd); 2509214571Sdim extsymoff = (elf_bad_symtab (abfd)) ? 0 : symtab_hdr->sh_info; 2510214571Sdim 2511214571Sdim name = bfd_get_section_name (abfd, sec); 2512214571Sdim 2513214571Sdim if (dynobj == NULL) 2514214571Sdim { 2515214571Sdim sgot = NULL; 2516214571Sdim g = NULL; 2517214571Sdim } 2518214571Sdim else 2519214571Sdim { 2520214571Sdim sgot = score_elf_got_section (dynobj, FALSE); 2521214571Sdim if (sgot == NULL) 2522214571Sdim g = NULL; 2523214571Sdim else 2524214571Sdim { 2525214571Sdim BFD_ASSERT (score_elf_section_data (sgot) != NULL); 2526214571Sdim g = score_elf_section_data (sgot)->u.got_info; 2527214571Sdim BFD_ASSERT (g != NULL); 2528214571Sdim } 2529214571Sdim } 2530214571Sdim 2531214571Sdim sreloc = NULL; 2532214571Sdim bed = get_elf_backend_data (abfd); 2533214571Sdim rel_end = relocs + sec->reloc_count * bed->s->int_rels_per_ext_rel; 2534214571Sdim for (rel = relocs; rel < rel_end; ++rel) 2535214571Sdim { 2536214571Sdim unsigned long r_symndx; 2537214571Sdim unsigned int r_type; 2538214571Sdim struct elf_link_hash_entry *h; 2539214571Sdim 2540214571Sdim r_symndx = ELF32_R_SYM (rel->r_info); 2541214571Sdim r_type = ELF32_R_TYPE (rel->r_info); 2542214571Sdim 2543214571Sdim if (r_symndx < extsymoff) 2544214571Sdim { 2545214571Sdim h = NULL; 2546214571Sdim } 2547214571Sdim else if (r_symndx >= extsymoff + NUM_SHDR_ENTRIES (symtab_hdr)) 2548214571Sdim { 2549273232Semaste (*_bfd_error_handler) (_("%B: Malformed reloc detected for section %s"), abfd, name); 2550214571Sdim bfd_set_error (bfd_error_bad_value); 2551214571Sdim return FALSE; 2552214571Sdim } 2553214571Sdim else 2554214571Sdim { 2555214571Sdim h = sym_hashes[r_symndx - extsymoff]; 2556214571Sdim 2557214571Sdim /* This may be an indirect symbol created because of a version. */ 2558214571Sdim if (h != NULL) 2559214571Sdim { 2560214571Sdim while (h->root.type == bfd_link_hash_indirect) 2561214571Sdim h = (struct elf_link_hash_entry *)h->root.u.i.link; 2562214571Sdim } 2563214571Sdim } 2564214571Sdim 2565214571Sdim /* Some relocs require a global offset table. */ 2566214571Sdim if (dynobj == NULL || sgot == NULL) 2567214571Sdim { 2568214571Sdim switch (r_type) 2569214571Sdim { 2570214571Sdim case R_SCORE_GOT15: 2571214571Sdim case R_SCORE_CALL15: 2572214571Sdim if (dynobj == NULL) 2573214571Sdim elf_hash_table (info)->dynobj = dynobj = abfd; 2574214571Sdim if (!score_elf_create_got_section (dynobj, info, FALSE)) 2575214571Sdim return FALSE; 2576214571Sdim g = score_elf_got_info (dynobj, &sgot); 2577214571Sdim break; 2578214571Sdim case R_SCORE_ABS32: 2579214571Sdim case R_SCORE_REL32: 2580214571Sdim if (dynobj == NULL && (info->shared || h != NULL) && (sec->flags & SEC_ALLOC) != 0) 2581214571Sdim elf_hash_table (info)->dynobj = dynobj = abfd; 2582214571Sdim break; 2583214571Sdim default: 2584214571Sdim break; 2585214571Sdim } 2586214571Sdim } 2587214571Sdim 2588214571Sdim if (!h && (r_type == R_SCORE_GOT_LO16)) 2589214571Sdim { 2590214571Sdim if (! score_elf_record_local_got_symbol (abfd, r_symndx, rel->r_addend, g)) 2591214571Sdim return FALSE; 2592214571Sdim } 2593214571Sdim 2594214571Sdim switch (r_type) 2595214571Sdim { 2596214571Sdim case R_SCORE_CALL15: 2597214571Sdim if (h == NULL) 2598214571Sdim { 2599214571Sdim (*_bfd_error_handler) 2600214571Sdim (_("%B: CALL15 reloc at 0x%lx not against global symbol"), 2601214571Sdim abfd, (unsigned long) rel->r_offset); 2602214571Sdim bfd_set_error (bfd_error_bad_value); 2603214571Sdim return FALSE; 2604214571Sdim } 2605214571Sdim else 2606214571Sdim { 2607214571Sdim /* This symbol requires a global offset table entry. */ 2608214571Sdim if (! score_elf_record_global_got_symbol (h, abfd, info, g)) 2609214571Sdim return FALSE; 2610214571Sdim 2611214571Sdim /* We need a stub, not a plt entry for the undefined function. But we record 2612214571Sdim it as if it needs plt. See _bfd_elf_adjust_dynamic_symbol. */ 2613214571Sdim h->needs_plt = 1; 2614214571Sdim h->type = STT_FUNC; 2615214571Sdim } 2616214571Sdim break; 2617214571Sdim case R_SCORE_GOT15: 2618214571Sdim if (h && ! score_elf_record_global_got_symbol (h, abfd, info, g)) 2619214571Sdim return FALSE; 2620214571Sdim break; 2621214571Sdim case R_SCORE_ABS32: 2622214571Sdim case R_SCORE_REL32: 2623214571Sdim if ((info->shared || h != NULL) && (sec->flags & SEC_ALLOC) != 0) 2624214571Sdim { 2625214571Sdim if (sreloc == NULL) 2626214571Sdim { 2627214571Sdim sreloc = score_elf_rel_dyn_section (dynobj, TRUE); 2628214571Sdim if (sreloc == NULL) 2629214571Sdim return FALSE; 2630214571Sdim } 2631214571Sdim#define SCORE_READONLY_SECTION (SEC_ALLOC | SEC_LOAD | SEC_READONLY) 2632214571Sdim if (info->shared) 2633214571Sdim { 2634214571Sdim /* When creating a shared object, we must copy these reloc types into 2635214571Sdim the output file as R_SCORE_REL32 relocs. We make room for this reloc 2636214571Sdim in the .rel.dyn reloc section. */ 2637214571Sdim score_elf_allocate_dynamic_relocations (dynobj, 1); 2638214571Sdim if ((sec->flags & SCORE_READONLY_SECTION) 2639214571Sdim == SCORE_READONLY_SECTION) 2640214571Sdim /* We tell the dynamic linker that there are 2641214571Sdim relocations against the text segment. */ 2642214571Sdim info->flags |= DF_TEXTREL; 2643214571Sdim } 2644214571Sdim else 2645214571Sdim { 2646214571Sdim struct score_elf_link_hash_entry *hscore; 2647214571Sdim 2648214571Sdim /* We only need to copy this reloc if the symbol is 2649214571Sdim defined in a dynamic object. */ 2650214571Sdim hscore = (struct score_elf_link_hash_entry *)h; 2651214571Sdim ++hscore->possibly_dynamic_relocs; 2652214571Sdim if ((sec->flags & SCORE_READONLY_SECTION) 2653214571Sdim == SCORE_READONLY_SECTION) 2654214571Sdim /* We need it to tell the dynamic linker if there 2655214571Sdim are relocations against the text segment. */ 2656214571Sdim hscore->readonly_reloc = TRUE; 2657214571Sdim } 2658214571Sdim 2659214571Sdim /* Even though we don't directly need a GOT entry for this symbol, 2660214571Sdim a symbol must have a dynamic symbol table index greater that 2661214571Sdim DT_SCORE_GOTSYM if there are dynamic relocations against it. */ 2662214571Sdim if (h != NULL) 2663214571Sdim { 2664214571Sdim if (dynobj == NULL) 2665214571Sdim elf_hash_table (info)->dynobj = dynobj = abfd; 2666214571Sdim if (! score_elf_create_got_section (dynobj, info, TRUE)) 2667214571Sdim return FALSE; 2668214571Sdim g = score_elf_got_info (dynobj, &sgot); 2669214571Sdim if (! score_elf_record_global_got_symbol (h, abfd, info, g)) 2670214571Sdim return FALSE; 2671214571Sdim } 2672214571Sdim } 2673214571Sdim break; 2674214571Sdim 2675214571Sdim /* This relocation describes the C++ object vtable hierarchy. 2676214571Sdim Reconstruct it for later use during GC. */ 2677214571Sdim case R_SCORE_GNU_VTINHERIT: 2678214571Sdim if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) 2679214571Sdim return FALSE; 2680214571Sdim break; 2681214571Sdim 2682214571Sdim /* This relocation describes which C++ vtable entries are actually 2683214571Sdim used. Record for later use during GC. */ 2684214571Sdim case R_SCORE_GNU_VTENTRY: 2685214571Sdim if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset)) 2686214571Sdim return FALSE; 2687214571Sdim break; 2688214571Sdim default: 2689214571Sdim break; 2690214571Sdim } 2691214571Sdim 2692214571Sdim /* We must not create a stub for a symbol that has relocations 2693214571Sdim related to taking the function's address. */ 2694214571Sdim switch (r_type) 2695214571Sdim { 2696214571Sdim default: 2697214571Sdim if (h != NULL) 2698214571Sdim { 2699214571Sdim struct score_elf_link_hash_entry *sh; 2700214571Sdim 2701214571Sdim sh = (struct score_elf_link_hash_entry *) h; 2702214571Sdim sh->no_fn_stub = TRUE; 2703214571Sdim } 2704214571Sdim break; 2705214571Sdim case R_SCORE_CALL15: 2706214571Sdim break; 2707214571Sdim } 2708214571Sdim } 2709214571Sdim 2710214571Sdim return TRUE; 2711214571Sdim} 2712214571Sdim 2713214571Sdimstatic bfd_boolean 2714214571Sdim_bfd_score_elf_add_symbol_hook (bfd *abfd, 2715214571Sdim struct bfd_link_info *info ATTRIBUTE_UNUSED, 2716214571Sdim Elf_Internal_Sym *sym, 2717214571Sdim const char **namep ATTRIBUTE_UNUSED, 2718214571Sdim flagword *flagsp ATTRIBUTE_UNUSED, 2719214571Sdim asection **secp, 2720214571Sdim bfd_vma *valp) 2721214571Sdim{ 2722214571Sdim switch (sym->st_shndx) 2723214571Sdim { 2724214571Sdim case SHN_COMMON: 2725214571Sdim if (sym->st_size > elf_gp_size (abfd)) 2726214571Sdim break; 2727214571Sdim /* Fall through. */ 2728214571Sdim case SHN_SCORE_SCOMMON: 2729214571Sdim *secp = bfd_make_section_old_way (abfd, ".scommon"); 2730214571Sdim (*secp)->flags |= SEC_IS_COMMON; 2731214571Sdim *valp = sym->st_size; 2732214571Sdim break; 2733214571Sdim } 2734214571Sdim 2735214571Sdim return TRUE; 2736214571Sdim} 2737214571Sdim 2738214571Sdimstatic void 2739214571Sdim_bfd_score_elf_symbol_processing (bfd *abfd, asymbol *asym) 2740214571Sdim{ 2741214571Sdim elf_symbol_type *elfsym; 2742214571Sdim 2743214571Sdim elfsym = (elf_symbol_type *) asym; 2744214571Sdim switch (elfsym->internal_elf_sym.st_shndx) 2745214571Sdim { 2746214571Sdim case SHN_COMMON: 2747214571Sdim if (asym->value > elf_gp_size (abfd)) 2748214571Sdim break; 2749214571Sdim /* Fall through. */ 2750214571Sdim case SHN_SCORE_SCOMMON: 2751214571Sdim if (score_elf_scom_section.name == NULL) 2752214571Sdim { 2753214571Sdim /* Initialize the small common section. */ 2754214571Sdim score_elf_scom_section.name = ".scommon"; 2755214571Sdim score_elf_scom_section.flags = SEC_IS_COMMON; 2756214571Sdim score_elf_scom_section.output_section = &score_elf_scom_section; 2757214571Sdim score_elf_scom_section.symbol = &score_elf_scom_symbol; 2758214571Sdim score_elf_scom_section.symbol_ptr_ptr = &score_elf_scom_symbol_ptr; 2759214571Sdim score_elf_scom_symbol.name = ".scommon"; 2760214571Sdim score_elf_scom_symbol.flags = BSF_SECTION_SYM; 2761214571Sdim score_elf_scom_symbol.section = &score_elf_scom_section; 2762214571Sdim score_elf_scom_symbol_ptr = &score_elf_scom_symbol; 2763214571Sdim } 2764214571Sdim asym->section = &score_elf_scom_section; 2765214571Sdim asym->value = elfsym->internal_elf_sym.st_size; 2766214571Sdim break; 2767214571Sdim } 2768214571Sdim} 2769214571Sdim 2770214571Sdimstatic bfd_boolean 2771214571Sdim_bfd_score_elf_link_output_symbol_hook (struct bfd_link_info *info ATTRIBUTE_UNUSED, 2772214571Sdim const char *name ATTRIBUTE_UNUSED, 2773214571Sdim Elf_Internal_Sym *sym, 2774214571Sdim asection *input_sec, 2775214571Sdim struct elf_link_hash_entry *h ATTRIBUTE_UNUSED) 2776214571Sdim{ 2777214571Sdim /* If we see a common symbol, which implies a relocatable link, then 2778214571Sdim if a symbol was small common in an input file, mark it as small 2779214571Sdim common in the output file. */ 2780214571Sdim if (sym->st_shndx == SHN_COMMON && strcmp (input_sec->name, ".scommon") == 0) 2781214571Sdim sym->st_shndx = SHN_SCORE_SCOMMON; 2782214571Sdim 2783214571Sdim return TRUE; 2784214571Sdim} 2785214571Sdim 2786214571Sdimstatic bfd_boolean 2787214571Sdim_bfd_score_elf_section_from_bfd_section (bfd *abfd ATTRIBUTE_UNUSED, 2788214571Sdim asection *sec, 2789214571Sdim int *retval) 2790214571Sdim{ 2791214571Sdim if (strcmp (bfd_get_section_name (abfd, sec), ".scommon") == 0) 2792214571Sdim { 2793214571Sdim *retval = SHN_SCORE_SCOMMON; 2794214571Sdim return TRUE; 2795214571Sdim } 2796214571Sdim 2797214571Sdim return FALSE; 2798214571Sdim} 2799214571Sdim 2800214571Sdim/* Adjust a symbol defined by a dynamic object and referenced by a 2801214571Sdim regular object. The current definition is in some section of the 2802214571Sdim dynamic object, but we're not including those sections. We have to 2803214571Sdim change the definition to something the rest of the link can understand. */ 2804214571Sdim 2805214571Sdimstatic bfd_boolean 2806214571Sdim_bfd_score_elf_adjust_dynamic_symbol (struct bfd_link_info *info, 2807214571Sdim struct elf_link_hash_entry *h) 2808214571Sdim{ 2809214571Sdim bfd *dynobj; 2810214571Sdim struct score_elf_link_hash_entry *hscore; 2811214571Sdim asection *s; 2812214571Sdim 2813214571Sdim dynobj = elf_hash_table (info)->dynobj; 2814214571Sdim 2815214571Sdim /* Make sure we know what is going on here. */ 2816214571Sdim BFD_ASSERT (dynobj != NULL 2817214571Sdim && (h->needs_plt 2818214571Sdim || h->u.weakdef != NULL 2819214571Sdim || (h->def_dynamic && h->ref_regular && !h->def_regular))); 2820214571Sdim 2821214571Sdim /* If this symbol is defined in a dynamic object, we need to copy 2822214571Sdim any R_SCORE_ABS32 or R_SCORE_REL32 relocs against it into the output 2823214571Sdim file. */ 2824214571Sdim hscore = (struct score_elf_link_hash_entry *)h; 2825214571Sdim if (!info->relocatable 2826214571Sdim && hscore->possibly_dynamic_relocs != 0 2827214571Sdim && (h->root.type == bfd_link_hash_defweak || !h->def_regular)) 2828214571Sdim { 2829214571Sdim score_elf_allocate_dynamic_relocations (dynobj, hscore->possibly_dynamic_relocs); 2830214571Sdim if (hscore->readonly_reloc) 2831214571Sdim /* We tell the dynamic linker that there are relocations 2832214571Sdim against the text segment. */ 2833214571Sdim info->flags |= DF_TEXTREL; 2834214571Sdim } 2835214571Sdim 2836214571Sdim /* For a function, create a stub, if allowed. */ 2837214571Sdim if (!hscore->no_fn_stub && h->needs_plt) 2838214571Sdim { 2839214571Sdim if (!elf_hash_table (info)->dynamic_sections_created) 2840214571Sdim return TRUE; 2841214571Sdim 2842214571Sdim /* If this symbol is not defined in a regular file, then set 2843214571Sdim the symbol to the stub location. This is required to make 2844214571Sdim function pointers compare as equal between the normal 2845214571Sdim executable and the shared library. */ 2846214571Sdim if (!h->def_regular) 2847214571Sdim { 2848214571Sdim /* We need .stub section. */ 2849214571Sdim s = bfd_get_section_by_name (dynobj, SCORE_ELF_STUB_SECTION_NAME); 2850214571Sdim BFD_ASSERT (s != NULL); 2851214571Sdim 2852214571Sdim h->root.u.def.section = s; 2853214571Sdim h->root.u.def.value = s->size; 2854214571Sdim 2855214571Sdim /* XXX Write this stub address somewhere. */ 2856214571Sdim h->plt.offset = s->size; 2857214571Sdim 2858214571Sdim /* Make room for this stub code. */ 2859214571Sdim s->size += SCORE_FUNCTION_STUB_SIZE; 2860214571Sdim 2861214571Sdim /* The last half word of the stub will be filled with the index 2862214571Sdim of this symbol in .dynsym section. */ 2863214571Sdim return TRUE; 2864214571Sdim } 2865214571Sdim } 2866214571Sdim else if ((h->type == STT_FUNC) && !h->needs_plt) 2867214571Sdim { 2868214571Sdim /* This will set the entry for this symbol in the GOT to 0, and 2869214571Sdim the dynamic linker will take care of this. */ 2870214571Sdim h->root.u.def.value = 0; 2871214571Sdim return TRUE; 2872214571Sdim } 2873214571Sdim 2874214571Sdim /* If this is a weak symbol, and there is a real definition, the 2875214571Sdim processor independent code will have arranged for us to see the 2876214571Sdim real definition first, and we can just use the same value. */ 2877214571Sdim if (h->u.weakdef != NULL) 2878214571Sdim { 2879214571Sdim BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined 2880214571Sdim || h->u.weakdef->root.type == bfd_link_hash_defweak); 2881214571Sdim h->root.u.def.section = h->u.weakdef->root.u.def.section; 2882214571Sdim h->root.u.def.value = h->u.weakdef->root.u.def.value; 2883214571Sdim return TRUE; 2884214571Sdim } 2885214571Sdim 2886214571Sdim /* This is a reference to a symbol defined by a dynamic object which 2887214571Sdim is not a function. */ 2888214571Sdim return TRUE; 2889214571Sdim} 2890214571Sdim 2891214571Sdim/* This function is called after all the input files have been read, 2892214571Sdim and the input sections have been assigned to output sections. */ 2893214571Sdim 2894214571Sdimstatic bfd_boolean 2895214571Sdim_bfd_score_elf_always_size_sections (bfd *output_bfd, 2896214571Sdim struct bfd_link_info *info) 2897214571Sdim{ 2898214571Sdim bfd *dynobj; 2899214571Sdim asection *s; 2900214571Sdim struct score_got_info *g; 2901214571Sdim int i; 2902214571Sdim bfd_size_type loadable_size = 0; 2903214571Sdim bfd_size_type local_gotno; 2904214571Sdim bfd *sub; 2905214571Sdim 2906214571Sdim dynobj = elf_hash_table (info)->dynobj; 2907214571Sdim if (dynobj == NULL) 2908214571Sdim /* Relocatable links don't have it. */ 2909214571Sdim return TRUE; 2910214571Sdim 2911214571Sdim g = score_elf_got_info (dynobj, &s); 2912214571Sdim if (s == NULL) 2913214571Sdim return TRUE; 2914214571Sdim 2915214571Sdim /* Calculate the total loadable size of the output. That will give us the 2916214571Sdim maximum number of GOT_PAGE entries required. */ 2917214571Sdim for (sub = info->input_bfds; sub; sub = sub->link_next) 2918214571Sdim { 2919214571Sdim asection *subsection; 2920214571Sdim 2921214571Sdim for (subsection = sub->sections; 2922214571Sdim subsection; 2923214571Sdim subsection = subsection->next) 2924214571Sdim { 2925214571Sdim if ((subsection->flags & SEC_ALLOC) == 0) 2926214571Sdim continue; 2927214571Sdim loadable_size += ((subsection->size + 0xf) 2928214571Sdim &~ (bfd_size_type) 0xf); 2929214571Sdim } 2930214571Sdim } 2931214571Sdim 2932214571Sdim /* There has to be a global GOT entry for every symbol with 2933214571Sdim a dynamic symbol table index of DT_SCORE_GOTSYM or 2934214571Sdim higher. Therefore, it make sense to put those symbols 2935214571Sdim that need GOT entries at the end of the symbol table. We 2936214571Sdim do that here. */ 2937214571Sdim if (! score_elf_sort_hash_table (info, 1)) 2938214571Sdim return FALSE; 2939214571Sdim 2940214571Sdim if (g->global_gotsym != NULL) 2941214571Sdim i = elf_hash_table (info)->dynsymcount - g->global_gotsym->dynindx; 2942214571Sdim else 2943214571Sdim /* If there are no global symbols, or none requiring 2944214571Sdim relocations, then GLOBAL_GOTSYM will be NULL. */ 2945214571Sdim i = 0; 2946214571Sdim 2947214571Sdim /* In the worst case, we'll get one stub per dynamic symbol. */ 2948214571Sdim loadable_size += SCORE_FUNCTION_STUB_SIZE * i; 2949214571Sdim 2950214571Sdim /* Assume there are two loadable segments consisting of 2951214571Sdim contiguous sections. Is 5 enough? */ 2952214571Sdim local_gotno = (loadable_size >> 16) + 5; 2953214571Sdim 2954214571Sdim g->local_gotno += local_gotno; 2955214571Sdim s->size += g->local_gotno * SCORE_ELF_GOT_SIZE (output_bfd); 2956214571Sdim 2957214571Sdim g->global_gotno = i; 2958214571Sdim s->size += i * SCORE_ELF_GOT_SIZE (output_bfd); 2959214571Sdim 2960214571Sdim score_elf_resolve_final_got_entries (g); 2961214571Sdim 2962214571Sdim if (s->size > SCORE_ELF_GOT_MAX_SIZE (output_bfd)) 2963214571Sdim { 2964214571Sdim /* Fixme. Error message or Warning message should be issued here. */ 2965214571Sdim } 2966214571Sdim 2967214571Sdim return TRUE; 2968214571Sdim} 2969214571Sdim 2970214571Sdim/* Set the sizes of the dynamic sections. */ 2971214571Sdim 2972214571Sdimstatic bfd_boolean 2973214571Sdim_bfd_score_elf_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) 2974214571Sdim{ 2975214571Sdim bfd *dynobj; 2976214571Sdim asection *s; 2977214571Sdim bfd_boolean reltext; 2978214571Sdim 2979214571Sdim dynobj = elf_hash_table (info)->dynobj; 2980214571Sdim BFD_ASSERT (dynobj != NULL); 2981214571Sdim 2982214571Sdim if (elf_hash_table (info)->dynamic_sections_created) 2983214571Sdim { 2984214571Sdim /* Set the contents of the .interp section to the interpreter. */ 2985214571Sdim if (!info->shared) 2986214571Sdim { 2987214571Sdim s = bfd_get_section_by_name (dynobj, ".interp"); 2988214571Sdim BFD_ASSERT (s != NULL); 2989214571Sdim s->size = strlen (ELF_DYNAMIC_INTERPRETER) + 1; 2990214571Sdim s->contents = (bfd_byte *) ELF_DYNAMIC_INTERPRETER; 2991214571Sdim } 2992214571Sdim } 2993214571Sdim 2994214571Sdim /* The check_relocs and adjust_dynamic_symbol entry points have 2995214571Sdim determined the sizes of the various dynamic sections. Allocate 2996214571Sdim memory for them. */ 2997214571Sdim reltext = FALSE; 2998214571Sdim for (s = dynobj->sections; s != NULL; s = s->next) 2999214571Sdim { 3000214571Sdim const char *name; 3001214571Sdim 3002214571Sdim if ((s->flags & SEC_LINKER_CREATED) == 0) 3003214571Sdim continue; 3004214571Sdim 3005214571Sdim /* It's OK to base decisions on the section name, because none 3006214571Sdim of the dynobj section names depend upon the input files. */ 3007214571Sdim name = bfd_get_section_name (dynobj, s); 3008214571Sdim 3009214571Sdim if (CONST_STRNEQ (name, ".rel")) 3010214571Sdim { 3011214571Sdim if (s->size == 0) 3012214571Sdim { 3013214571Sdim /* We only strip the section if the output section name 3014214571Sdim has the same name. Otherwise, there might be several 3015214571Sdim input sections for this output section. FIXME: This 3016214571Sdim code is probably not needed these days anyhow, since 3017214571Sdim the linker now does not create empty output sections. */ 3018214571Sdim if (s->output_section != NULL 3019214571Sdim && strcmp (name, 3020214571Sdim bfd_get_section_name (s->output_section->owner, 3021214571Sdim s->output_section)) == 0) 3022214571Sdim s->flags |= SEC_EXCLUDE; 3023214571Sdim } 3024214571Sdim else 3025214571Sdim { 3026214571Sdim const char *outname; 3027214571Sdim asection *target; 3028214571Sdim 3029214571Sdim /* If this relocation section applies to a read only 3030214571Sdim section, then we probably need a DT_TEXTREL entry. 3031214571Sdim If the relocation section is .rel.dyn, we always 3032214571Sdim assert a DT_TEXTREL entry rather than testing whether 3033214571Sdim there exists a relocation to a read only section or 3034214571Sdim not. */ 3035214571Sdim outname = bfd_get_section_name (output_bfd, s->output_section); 3036214571Sdim target = bfd_get_section_by_name (output_bfd, outname + 4); 3037214571Sdim if ((target != NULL 3038214571Sdim && (target->flags & SEC_READONLY) != 0 3039214571Sdim && (target->flags & SEC_ALLOC) != 0) || strcmp (outname, ".rel.dyn") == 0) 3040214571Sdim reltext = TRUE; 3041214571Sdim 3042214571Sdim /* We use the reloc_count field as a counter if we need 3043214571Sdim to copy relocs into the output file. */ 3044214571Sdim if (strcmp (name, ".rel.dyn") != 0) 3045214571Sdim s->reloc_count = 0; 3046214571Sdim } 3047214571Sdim } 3048214571Sdim else if (CONST_STRNEQ (name, ".got")) 3049214571Sdim { 3050214571Sdim /* _bfd_score_elf_always_size_sections() has already done 3051214571Sdim most of the work, but some symbols may have been mapped 3052214571Sdim to versions that we must now resolve in the got_entries 3053214571Sdim hash tables. */ 3054214571Sdim } 3055214571Sdim else if (strcmp (name, SCORE_ELF_STUB_SECTION_NAME) == 0) 3056214571Sdim { 3057214571Sdim /* IRIX rld assumes that the function stub isn't at the end 3058214571Sdim of .text section. So put a dummy. XXX */ 3059214571Sdim s->size += SCORE_FUNCTION_STUB_SIZE; 3060214571Sdim } 3061214571Sdim else if (! CONST_STRNEQ (name, ".init")) 3062214571Sdim { 3063214571Sdim /* It's not one of our sections, so don't allocate space. */ 3064214571Sdim continue; 3065214571Sdim } 3066214571Sdim 3067214571Sdim /* Allocate memory for the section contents. */ 3068214571Sdim s->contents = bfd_zalloc (dynobj, s->size); 3069214571Sdim if (s->contents == NULL && s->size != 0) 3070214571Sdim { 3071214571Sdim bfd_set_error (bfd_error_no_memory); 3072214571Sdim return FALSE; 3073214571Sdim } 3074214571Sdim } 3075214571Sdim 3076214571Sdim if (elf_hash_table (info)->dynamic_sections_created) 3077214571Sdim { 3078214571Sdim /* Add some entries to the .dynamic section. We fill in the 3079214571Sdim values later, in _bfd_score_elf_finish_dynamic_sections, but we 3080214571Sdim must add the entries now so that we get the correct size for 3081214571Sdim the .dynamic section. The DT_DEBUG entry is filled in by the 3082214571Sdim dynamic linker and used by the debugger. */ 3083214571Sdim 3084214571Sdim if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_DEBUG, 0)) 3085214571Sdim return FALSE; 3086214571Sdim 3087214571Sdim if (reltext) 3088214571Sdim info->flags |= DF_TEXTREL; 3089214571Sdim 3090214571Sdim if ((info->flags & DF_TEXTREL) != 0) 3091214571Sdim { 3092214571Sdim if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_TEXTREL, 0)) 3093214571Sdim return FALSE; 3094214571Sdim } 3095214571Sdim 3096214571Sdim if (! SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_PLTGOT, 0)) 3097214571Sdim return FALSE; 3098214571Sdim 3099214571Sdim if (score_elf_rel_dyn_section (dynobj, FALSE)) 3100214571Sdim { 3101214571Sdim if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_REL, 0)) 3102214571Sdim return FALSE; 3103214571Sdim 3104214571Sdim if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELSZ, 0)) 3105214571Sdim return FALSE; 3106214571Sdim 3107214571Sdim if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELENT, 0)) 3108214571Sdim return FALSE; 3109214571Sdim } 3110214571Sdim 3111214571Sdim if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_BASE_ADDRESS, 0)) 3112214571Sdim return FALSE; 3113214571Sdim 3114214571Sdim if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_LOCAL_GOTNO, 0)) 3115214571Sdim return FALSE; 3116214571Sdim 3117214571Sdim if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_SYMTABNO, 0)) 3118214571Sdim return FALSE; 3119214571Sdim 3120214571Sdim if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_UNREFEXTNO, 0)) 3121214571Sdim return FALSE; 3122214571Sdim 3123214571Sdim if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_GOTSYM, 0)) 3124214571Sdim return FALSE; 3125214571Sdim 3126214571Sdim if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_HIPAGENO, 0)) 3127214571Sdim return FALSE; 3128214571Sdim } 3129214571Sdim 3130214571Sdim return TRUE; 3131214571Sdim} 3132214571Sdim 3133214571Sdimstatic bfd_boolean 3134214571Sdim_bfd_score_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) 3135214571Sdim{ 3136214571Sdim struct elf_link_hash_entry *h; 3137214571Sdim struct bfd_link_hash_entry *bh; 3138214571Sdim flagword flags; 3139214571Sdim asection *s; 3140214571Sdim 3141214571Sdim flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY 3142214571Sdim | SEC_LINKER_CREATED | SEC_READONLY); 3143214571Sdim 3144214571Sdim /* ABI requests the .dynamic section to be read only. */ 3145214571Sdim s = bfd_get_section_by_name (abfd, ".dynamic"); 3146214571Sdim if (s != NULL) 3147214571Sdim { 3148214571Sdim if (!bfd_set_section_flags (abfd, s, flags)) 3149214571Sdim return FALSE; 3150214571Sdim } 3151214571Sdim 3152214571Sdim /* We need to create .got section. */ 3153214571Sdim if (!score_elf_create_got_section (abfd, info, FALSE)) 3154214571Sdim return FALSE; 3155214571Sdim 3156214571Sdim if (!score_elf_rel_dyn_section (elf_hash_table (info)->dynobj, TRUE)) 3157214571Sdim return FALSE; 3158214571Sdim 3159214571Sdim /* Create .stub section. */ 3160214571Sdim if (bfd_get_section_by_name (abfd, SCORE_ELF_STUB_SECTION_NAME) == NULL) 3161214571Sdim { 3162214571Sdim s = bfd_make_section_with_flags (abfd, SCORE_ELF_STUB_SECTION_NAME, 3163214571Sdim flags | SEC_CODE); 3164214571Sdim if (s == NULL 3165214571Sdim || !bfd_set_section_alignment (abfd, s, 2)) 3166214571Sdim 3167214571Sdim return FALSE; 3168214571Sdim } 3169214571Sdim 3170214571Sdim if (!info->shared) 3171214571Sdim { 3172214571Sdim const char *name; 3173214571Sdim 3174214571Sdim name = "_DYNAMIC_LINK"; 3175214571Sdim bh = NULL; 3176214571Sdim if (!(_bfd_generic_link_add_one_symbol 3177214571Sdim (info, abfd, name, BSF_GLOBAL, bfd_abs_section_ptr, 3178214571Sdim (bfd_vma) 0, (const char *)NULL, FALSE, get_elf_backend_data (abfd)->collect, &bh))) 3179214571Sdim return FALSE; 3180214571Sdim 3181214571Sdim h = (struct elf_link_hash_entry *)bh; 3182214571Sdim h->non_elf = 0; 3183214571Sdim h->def_regular = 1; 3184214571Sdim h->type = STT_SECTION; 3185214571Sdim 3186214571Sdim if (!bfd_elf_link_record_dynamic_symbol (info, h)) 3187214571Sdim return FALSE; 3188214571Sdim } 3189214571Sdim 3190214571Sdim return TRUE; 3191214571Sdim} 3192214571Sdim 3193214571Sdim 3194214571Sdim/* Finish up dynamic symbol handling. We set the contents of various 3195214571Sdim dynamic sections here. */ 3196214571Sdim 3197214571Sdimstatic bfd_boolean 3198214571Sdim_bfd_score_elf_finish_dynamic_symbol (bfd *output_bfd, 3199214571Sdim struct bfd_link_info *info, 3200214571Sdim struct elf_link_hash_entry *h, 3201214571Sdim Elf_Internal_Sym *sym) 3202214571Sdim{ 3203214571Sdim bfd *dynobj; 3204214571Sdim asection *sgot; 3205214571Sdim struct score_got_info *g; 3206214571Sdim const char *name; 3207214571Sdim 3208214571Sdim dynobj = elf_hash_table (info)->dynobj; 3209214571Sdim 3210214571Sdim if (h->plt.offset != MINUS_ONE) 3211214571Sdim { 3212214571Sdim asection *s; 3213214571Sdim bfd_byte stub[SCORE_FUNCTION_STUB_SIZE]; 3214214571Sdim 3215214571Sdim /* This symbol has a stub. Set it up. */ 3216214571Sdim BFD_ASSERT (h->dynindx != -1); 3217214571Sdim 3218214571Sdim s = bfd_get_section_by_name (dynobj, SCORE_ELF_STUB_SECTION_NAME); 3219214571Sdim BFD_ASSERT (s != NULL); 3220214571Sdim 3221214571Sdim /* FIXME: Can h->dynindex be more than 64K? */ 3222214571Sdim if (h->dynindx & 0xffff0000) 3223214571Sdim return FALSE; 3224214571Sdim 3225214571Sdim /* Fill the stub. */ 3226214571Sdim bfd_put_32 (output_bfd, STUB_LW, stub); 3227214571Sdim bfd_put_32 (output_bfd, STUB_MOVE, stub + 4); 3228214571Sdim bfd_put_32 (output_bfd, STUB_LI16 | (h->dynindx << 1), stub + 8); 3229214571Sdim bfd_put_32 (output_bfd, STUB_BRL, stub + 12); 3230214571Sdim 3231214571Sdim BFD_ASSERT (h->plt.offset <= s->size); 3232214571Sdim memcpy (s->contents + h->plt.offset, stub, SCORE_FUNCTION_STUB_SIZE); 3233214571Sdim 3234214571Sdim /* Mark the symbol as undefined. plt.offset != -1 occurs 3235214571Sdim only for the referenced symbol. */ 3236214571Sdim sym->st_shndx = SHN_UNDEF; 3237214571Sdim 3238214571Sdim /* The run-time linker uses the st_value field of the symbol 3239214571Sdim to reset the global offset table entry for this external 3240214571Sdim to its stub address when unlinking a shared object. */ 3241214571Sdim sym->st_value = (s->output_section->vma + s->output_offset + h->plt.offset); 3242214571Sdim } 3243214571Sdim 3244214571Sdim BFD_ASSERT (h->dynindx != -1 || h->forced_local); 3245214571Sdim 3246214571Sdim sgot = score_elf_got_section (dynobj, FALSE); 3247214571Sdim BFD_ASSERT (sgot != NULL); 3248214571Sdim BFD_ASSERT (score_elf_section_data (sgot) != NULL); 3249214571Sdim g = score_elf_section_data (sgot)->u.got_info; 3250214571Sdim BFD_ASSERT (g != NULL); 3251214571Sdim 3252214571Sdim /* Run through the global symbol table, creating GOT entries for all 3253214571Sdim the symbols that need them. */ 3254214571Sdim if (g->global_gotsym != NULL && h->dynindx >= g->global_gotsym->dynindx) 3255214571Sdim { 3256214571Sdim bfd_vma offset; 3257214571Sdim bfd_vma value; 3258214571Sdim 3259214571Sdim value = sym->st_value; 3260214571Sdim offset = score_elf_global_got_index (dynobj, h); 3261214571Sdim bfd_put_32 (output_bfd, value, sgot->contents + offset); 3262214571Sdim } 3263214571Sdim 3264214571Sdim /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */ 3265214571Sdim name = h->root.root.string; 3266214571Sdim if (strcmp (name, "_DYNAMIC") == 0 || strcmp (name, "_GLOBAL_OFFSET_TABLE_") == 0) 3267214571Sdim sym->st_shndx = SHN_ABS; 3268214571Sdim else if (strcmp (name, "_DYNAMIC_LINK") == 0) 3269214571Sdim { 3270214571Sdim sym->st_shndx = SHN_ABS; 3271214571Sdim sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION); 3272214571Sdim sym->st_value = 1; 3273214571Sdim } 3274214571Sdim else if (strcmp (name, GP_DISP_LABEL) == 0) 3275214571Sdim { 3276214571Sdim sym->st_shndx = SHN_ABS; 3277214571Sdim sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION); 3278214571Sdim sym->st_value = elf_gp (output_bfd); 3279214571Sdim } 3280214571Sdim 3281214571Sdim return TRUE; 3282214571Sdim} 3283214571Sdim 3284214571Sdim/* Finish up the dynamic sections. */ 3285214571Sdim 3286214571Sdimstatic bfd_boolean 3287214571Sdim_bfd_score_elf_finish_dynamic_sections (bfd *output_bfd, 3288214571Sdim struct bfd_link_info *info) 3289214571Sdim{ 3290214571Sdim bfd *dynobj; 3291214571Sdim asection *sdyn; 3292214571Sdim asection *sgot; 3293214571Sdim asection *s; 3294214571Sdim struct score_got_info *g; 3295214571Sdim 3296214571Sdim dynobj = elf_hash_table (info)->dynobj; 3297214571Sdim 3298214571Sdim sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); 3299214571Sdim 3300214571Sdim sgot = score_elf_got_section (dynobj, FALSE); 3301214571Sdim if (sgot == NULL) 3302214571Sdim g = NULL; 3303214571Sdim else 3304214571Sdim { 3305214571Sdim BFD_ASSERT (score_elf_section_data (sgot) != NULL); 3306214571Sdim g = score_elf_section_data (sgot)->u.got_info; 3307214571Sdim BFD_ASSERT (g != NULL); 3308214571Sdim } 3309214571Sdim 3310214571Sdim if (elf_hash_table (info)->dynamic_sections_created) 3311214571Sdim { 3312214571Sdim bfd_byte *b; 3313214571Sdim 3314214571Sdim BFD_ASSERT (sdyn != NULL); 3315214571Sdim BFD_ASSERT (g != NULL); 3316214571Sdim 3317214571Sdim for (b = sdyn->contents; 3318214571Sdim b < sdyn->contents + sdyn->size; 3319214571Sdim b += SCORE_ELF_DYN_SIZE (dynobj)) 3320214571Sdim { 3321214571Sdim Elf_Internal_Dyn dyn; 3322214571Sdim const char *name; 3323214571Sdim size_t elemsize; 3324214571Sdim bfd_boolean swap_out_p; 3325214571Sdim 3326214571Sdim /* Read in the current dynamic entry. */ 3327214571Sdim (*get_elf_backend_data (dynobj)->s->swap_dyn_in) (dynobj, b, &dyn); 3328214571Sdim 3329214571Sdim /* Assume that we're going to modify it and write it out. */ 3330214571Sdim swap_out_p = TRUE; 3331214571Sdim 3332214571Sdim switch (dyn.d_tag) 3333214571Sdim { 3334214571Sdim case DT_RELENT: 3335214571Sdim s = score_elf_rel_dyn_section (dynobj, FALSE); 3336214571Sdim BFD_ASSERT (s != NULL); 3337214571Sdim dyn.d_un.d_val = SCORE_ELF_REL_SIZE (dynobj); 3338214571Sdim break; 3339214571Sdim 3340214571Sdim case DT_STRSZ: 3341214571Sdim /* Rewrite DT_STRSZ. */ 3342214571Sdim dyn.d_un.d_val = _bfd_elf_strtab_size (elf_hash_table (info)->dynstr); 3343214571Sdim break; 3344214571Sdim 3345214571Sdim case DT_PLTGOT: 3346214571Sdim name = ".got"; 3347214571Sdim s = bfd_get_section_by_name (output_bfd, name); 3348214571Sdim BFD_ASSERT (s != NULL); 3349214571Sdim dyn.d_un.d_ptr = s->vma; 3350214571Sdim break; 3351214571Sdim 3352214571Sdim case DT_SCORE_BASE_ADDRESS: 3353214571Sdim s = output_bfd->sections; 3354214571Sdim BFD_ASSERT (s != NULL); 3355214571Sdim dyn.d_un.d_ptr = s->vma & ~(bfd_vma) 0xffff; 3356214571Sdim break; 3357214571Sdim 3358214571Sdim case DT_SCORE_LOCAL_GOTNO: 3359214571Sdim dyn.d_un.d_val = g->local_gotno; 3360214571Sdim break; 3361214571Sdim 3362214571Sdim case DT_SCORE_UNREFEXTNO: 3363214571Sdim /* The index into the dynamic symbol table which is the 3364214571Sdim entry of the first external symbol that is not 3365214571Sdim referenced within the same object. */ 3366214571Sdim dyn.d_un.d_val = bfd_count_sections (output_bfd) + 1; 3367214571Sdim break; 3368214571Sdim 3369214571Sdim case DT_SCORE_GOTSYM: 3370214571Sdim if (g->global_gotsym) 3371214571Sdim { 3372214571Sdim dyn.d_un.d_val = g->global_gotsym->dynindx; 3373214571Sdim break; 3374214571Sdim } 3375214571Sdim /* In case if we don't have global got symbols we default 3376214571Sdim to setting DT_SCORE_GOTSYM to the same value as 3377214571Sdim DT_SCORE_SYMTABNO, so we just fall through. */ 3378214571Sdim 3379214571Sdim case DT_SCORE_SYMTABNO: 3380214571Sdim name = ".dynsym"; 3381214571Sdim elemsize = SCORE_ELF_SYM_SIZE (output_bfd); 3382214571Sdim s = bfd_get_section_by_name (output_bfd, name); 3383214571Sdim BFD_ASSERT (s != NULL); 3384214571Sdim 3385214571Sdim dyn.d_un.d_val = s->size / elemsize; 3386214571Sdim break; 3387214571Sdim 3388214571Sdim case DT_SCORE_HIPAGENO: 3389214571Sdim dyn.d_un.d_val = g->local_gotno - SCORE_RESERVED_GOTNO; 3390214571Sdim break; 3391214571Sdim 3392214571Sdim default: 3393214571Sdim swap_out_p = FALSE; 3394214571Sdim break; 3395214571Sdim } 3396214571Sdim 3397214571Sdim if (swap_out_p) 3398214571Sdim (*get_elf_backend_data (dynobj)->s->swap_dyn_out) (dynobj, &dyn, b); 3399214571Sdim } 3400214571Sdim } 3401214571Sdim 3402214571Sdim /* The first entry of the global offset table will be filled at 3403214571Sdim runtime. The second entry will be used by some runtime loaders. 3404214571Sdim This isn't the case of IRIX rld. */ 3405214571Sdim if (sgot != NULL && sgot->size > 0) 3406214571Sdim { 3407214571Sdim bfd_put_32 (output_bfd, 0, sgot->contents); 3408214571Sdim bfd_put_32 (output_bfd, 0x80000000, sgot->contents + SCORE_ELF_GOT_SIZE (output_bfd)); 3409214571Sdim } 3410214571Sdim 3411214571Sdim if (sgot != NULL) 3412214571Sdim elf_section_data (sgot->output_section)->this_hdr.sh_entsize 3413214571Sdim = SCORE_ELF_GOT_SIZE (output_bfd); 3414214571Sdim 3415214571Sdim 3416214571Sdim /* We need to sort the entries of the dynamic relocation section. */ 3417214571Sdim s = score_elf_rel_dyn_section (dynobj, FALSE); 3418214571Sdim 3419214571Sdim if (s != NULL && s->size > (bfd_vma)2 * SCORE_ELF_REL_SIZE (output_bfd)) 3420214571Sdim { 3421214571Sdim reldyn_sorting_bfd = output_bfd; 3422214571Sdim qsort ((Elf32_External_Rel *) s->contents + 1, s->reloc_count - 1, 3423214571Sdim sizeof (Elf32_External_Rel), score_elf_sort_dynamic_relocs); 3424214571Sdim } 3425214571Sdim 3426214571Sdim return TRUE; 3427214571Sdim} 3428214571Sdim 3429214571Sdim/* This function set up the ELF section header for a BFD section in preparation for writing 3430214571Sdim it out. This is where the flags and type fields are set for unusual sections. */ 3431214571Sdim 3432214571Sdimstatic bfd_boolean 3433214571Sdim_bfd_score_elf_fake_sections (bfd *abfd ATTRIBUTE_UNUSED, 3434214571Sdim Elf_Internal_Shdr *hdr, 3435214571Sdim asection *sec) 3436214571Sdim{ 3437214571Sdim const char *name; 3438214571Sdim 3439214571Sdim name = bfd_get_section_name (abfd, sec); 3440214571Sdim 3441214571Sdim if (strcmp (name, ".got") == 0 3442214571Sdim || strcmp (name, ".srdata") == 0 3443214571Sdim || strcmp (name, ".sdata") == 0 3444214571Sdim || strcmp (name, ".sbss") == 0) 3445214571Sdim hdr->sh_flags |= SHF_SCORE_GPREL; 3446214571Sdim 3447214571Sdim return TRUE; 3448214571Sdim} 3449214571Sdim 3450214571Sdim/* This function do additional processing on the ELF section header before writing 3451214571Sdim it out. This is used to set the flags and type fields for some sections. */ 3452214571Sdim 3453214571Sdim/* assign_file_positions_except_relocs() check section flag and if it is allocatable, 3454214571Sdim warning message will be issued. backend_fake_section is called before 3455214571Sdim assign_file_positions_except_relocs(); backend_section_processing after it. so, we 3456214571Sdim modify section flag there, but not backend_fake_section. */ 3457214571Sdim 3458214571Sdimstatic bfd_boolean 3459214571Sdim_bfd_score_elf_section_processing (bfd *abfd ATTRIBUTE_UNUSED, Elf_Internal_Shdr *hdr) 3460214571Sdim{ 3461214571Sdim if (hdr->bfd_section != NULL) 3462214571Sdim { 3463214571Sdim const char *name = bfd_get_section_name (abfd, hdr->bfd_section); 3464214571Sdim 3465214571Sdim if (strcmp (name, ".sdata") == 0) 3466214571Sdim { 3467214571Sdim hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_SCORE_GPREL; 3468214571Sdim hdr->sh_type = SHT_PROGBITS; 3469214571Sdim } 3470214571Sdim else if (strcmp (name, ".sbss") == 0) 3471214571Sdim { 3472214571Sdim hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_SCORE_GPREL; 3473214571Sdim hdr->sh_type = SHT_NOBITS; 3474214571Sdim } 3475214571Sdim else if (strcmp (name, ".srdata") == 0) 3476214571Sdim { 3477214571Sdim hdr->sh_flags |= SHF_ALLOC | SHF_SCORE_GPREL; 3478214571Sdim hdr->sh_type = SHT_PROGBITS; 3479214571Sdim } 3480214571Sdim } 3481214571Sdim 3482214571Sdim return TRUE; 3483214571Sdim} 3484214571Sdim 3485214571Sdimstatic bfd_boolean 3486214571Sdim_bfd_score_elf_write_section (bfd *output_bfd, 3487214571Sdim struct bfd_link_info *link_info ATTRIBUTE_UNUSED, 3488214571Sdim asection *sec, bfd_byte *contents) 3489214571Sdim{ 3490214571Sdim bfd_byte *to, *from, *end; 3491214571Sdim int i; 3492214571Sdim 3493214571Sdim if (strcmp (sec->name, ".pdr") != 0) 3494214571Sdim return FALSE; 3495214571Sdim 3496214571Sdim if (score_elf_section_data (sec)->u.tdata == NULL) 3497214571Sdim return FALSE; 3498214571Sdim 3499214571Sdim to = contents; 3500214571Sdim end = contents + sec->size; 3501214571Sdim for (from = contents, i = 0; from < end; from += PDR_SIZE, i++) 3502214571Sdim { 3503214571Sdim if ((score_elf_section_data (sec)->u.tdata)[i] == 1) 3504214571Sdim continue; 3505214571Sdim 3506214571Sdim if (to != from) 3507214571Sdim memcpy (to, from, PDR_SIZE); 3508214571Sdim 3509214571Sdim to += PDR_SIZE; 3510214571Sdim } 3511214571Sdim bfd_set_section_contents (output_bfd, sec->output_section, contents, 3512214571Sdim (file_ptr) sec->output_offset, sec->size); 3513214571Sdim 3514214571Sdim return TRUE; 3515214571Sdim} 3516214571Sdim 3517214571Sdim/* Copy data from a SCORE ELF indirect symbol to its direct symbol, hiding the old 3518214571Sdim indirect symbol. Process additional relocation information. */ 3519214571Sdim 3520214571Sdimstatic void 3521214571Sdim_bfd_score_elf_copy_indirect_symbol (struct bfd_link_info *info, 3522214571Sdim struct elf_link_hash_entry *dir, 3523214571Sdim struct elf_link_hash_entry *ind) 3524214571Sdim{ 3525214571Sdim struct score_elf_link_hash_entry *dirscore, *indscore; 3526214571Sdim 3527214571Sdim _bfd_elf_link_hash_copy_indirect (info, dir, ind); 3528214571Sdim 3529214571Sdim if (ind->root.type != bfd_link_hash_indirect) 3530214571Sdim return; 3531214571Sdim 3532214571Sdim dirscore = (struct score_elf_link_hash_entry *) dir; 3533214571Sdim indscore = (struct score_elf_link_hash_entry *) ind; 3534214571Sdim dirscore->possibly_dynamic_relocs += indscore->possibly_dynamic_relocs; 3535214571Sdim 3536214571Sdim if (indscore->readonly_reloc) 3537214571Sdim dirscore->readonly_reloc = TRUE; 3538214571Sdim 3539214571Sdim if (indscore->no_fn_stub) 3540214571Sdim dirscore->no_fn_stub = TRUE; 3541214571Sdim} 3542214571Sdim 3543214571Sdim/* Remove information about discarded functions from other sections which mention them. */ 3544214571Sdim 3545214571Sdimstatic bfd_boolean 3546214571Sdim_bfd_score_elf_discard_info (bfd *abfd, struct elf_reloc_cookie *cookie, 3547214571Sdim struct bfd_link_info *info) 3548214571Sdim{ 3549214571Sdim asection *o; 3550214571Sdim bfd_boolean ret = FALSE; 3551214571Sdim unsigned char *tdata; 3552214571Sdim size_t i, skip; 3553214571Sdim 3554214571Sdim o = bfd_get_section_by_name (abfd, ".pdr"); 3555214571Sdim if ((!o) || (o->size == 0) || (o->size % PDR_SIZE != 0) 3556214571Sdim || (o->output_section != NULL && bfd_is_abs_section (o->output_section))) 3557214571Sdim return FALSE; 3558214571Sdim 3559214571Sdim tdata = bfd_zmalloc (o->size / PDR_SIZE); 3560214571Sdim if (!tdata) 3561214571Sdim return FALSE; 3562214571Sdim 3563214571Sdim cookie->rels = _bfd_elf_link_read_relocs (abfd, o, NULL, NULL, info->keep_memory); 3564214571Sdim if (!cookie->rels) 3565214571Sdim { 3566214571Sdim free (tdata); 3567214571Sdim return FALSE; 3568214571Sdim } 3569214571Sdim 3570214571Sdim cookie->rel = cookie->rels; 3571214571Sdim cookie->relend = cookie->rels + o->reloc_count; 3572214571Sdim 3573214571Sdim for (i = 0, skip = 0; i < o->size; i++) 3574214571Sdim { 3575214571Sdim if (bfd_elf_reloc_symbol_deleted_p (i * PDR_SIZE, cookie)) 3576214571Sdim { 3577214571Sdim tdata[i] = 1; 3578214571Sdim skip++; 3579214571Sdim } 3580214571Sdim } 3581214571Sdim 3582214571Sdim if (skip != 0) 3583214571Sdim { 3584214571Sdim score_elf_section_data (o)->u.tdata = tdata; 3585214571Sdim o->size -= skip * PDR_SIZE; 3586214571Sdim ret = TRUE; 3587214571Sdim } 3588214571Sdim else 3589214571Sdim free (tdata); 3590214571Sdim 3591214571Sdim if (!info->keep_memory) 3592214571Sdim free (cookie->rels); 3593214571Sdim 3594214571Sdim return ret; 3595214571Sdim} 3596214571Sdim 3597214571Sdim/* Signal that discard_info() has removed the discarded relocations for this section. */ 3598214571Sdim 3599214571Sdimstatic bfd_boolean 3600214571Sdim_bfd_score_elf_ignore_discarded_relocs (asection *sec) 3601214571Sdim{ 3602214571Sdim if (strcmp (sec->name, ".pdr") == 0) 3603214571Sdim return TRUE; 3604214571Sdim return FALSE; 3605214571Sdim} 3606214571Sdim 3607214571Sdim/* Return the section that should be marked against GC for a given 3608214571Sdim relocation. */ 3609214571Sdim 3610214571Sdimstatic asection * 3611214571Sdim_bfd_score_elf_gc_mark_hook (asection *sec, 3612214571Sdim struct bfd_link_info *info, 3613214571Sdim Elf_Internal_Rela *rel, 3614214571Sdim struct elf_link_hash_entry *h, 3615214571Sdim Elf_Internal_Sym *sym) 3616214571Sdim{ 3617214571Sdim if (h != NULL) 3618214571Sdim switch (ELF32_R_TYPE (rel->r_info)) 3619214571Sdim { 3620214571Sdim case R_SCORE_GNU_VTINHERIT: 3621214571Sdim case R_SCORE_GNU_VTENTRY: 3622214571Sdim return NULL; 3623214571Sdim } 3624214571Sdim 3625214571Sdim return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); 3626214571Sdim} 3627214571Sdim 3628214571Sdim/* Support for core dump NOTE sections. */ 3629214571Sdim 3630214571Sdimstatic bfd_boolean 3631214571Sdim_bfd_score_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) 3632214571Sdim{ 3633214571Sdim int offset; 3634214571Sdim unsigned int raw_size; 3635214571Sdim 3636214571Sdim switch (note->descsz) 3637214571Sdim { 3638214571Sdim default: 3639214571Sdim return FALSE; 3640214571Sdim 3641214571Sdim case 148: /* Linux/Score 32-bit. */ 3642214571Sdim /* pr_cursig */ 3643214571Sdim elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12); 3644214571Sdim 3645214571Sdim /* pr_pid */ 3646214571Sdim elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 24); 3647214571Sdim 3648214571Sdim /* pr_reg */ 3649214571Sdim offset = 72; 3650214571Sdim raw_size = 72; 3651214571Sdim 3652214571Sdim break; 3653214571Sdim } 3654214571Sdim 3655214571Sdim /* Make a ".reg/999" section. */ 3656214571Sdim return _bfd_elfcore_make_pseudosection (abfd, ".reg", raw_size, note->descpos + offset); 3657214571Sdim} 3658214571Sdim 3659214571Sdimstatic bfd_boolean 3660214571Sdim_bfd_score_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) 3661214571Sdim{ 3662214571Sdim switch (note->descsz) 3663214571Sdim { 3664214571Sdim default: 3665214571Sdim return FALSE; 3666214571Sdim 3667214571Sdim case 124: /* Linux/Score elf_prpsinfo. */ 3668214571Sdim elf_tdata (abfd)->core_program = _bfd_elfcore_strndup (abfd, note->descdata + 28, 16); 3669214571Sdim elf_tdata (abfd)->core_command = _bfd_elfcore_strndup (abfd, note->descdata + 44, 80); 3670214571Sdim } 3671214571Sdim 3672214571Sdim /* Note that for some reason, a spurious space is tacked 3673214571Sdim onto the end of the args in some (at least one anyway) 3674214571Sdim implementations, so strip it off if it exists. */ 3675214571Sdim 3676214571Sdim { 3677214571Sdim char *command = elf_tdata (abfd)->core_command; 3678214571Sdim int n = strlen (command); 3679214571Sdim 3680214571Sdim if (0 < n && command[n - 1] == ' ') 3681214571Sdim command[n - 1] = '\0'; 3682214571Sdim } 3683214571Sdim 3684214571Sdim return TRUE; 3685214571Sdim} 3686214571Sdim 3687214571Sdim 3688214571Sdim/* Score BFD functions. */ 3689214571Sdim 3690214571Sdimstatic reloc_howto_type * 3691214571Sdimelf32_score_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, bfd_reloc_code_real_type code) 3692214571Sdim{ 3693214571Sdim unsigned int i; 3694214571Sdim 3695214571Sdim for (i = 0; i < NUM_ELEM (elf32_score_reloc_map); i++) 3696214571Sdim if (elf32_score_reloc_map[i].bfd_reloc_val == code) 3697214571Sdim return &elf32_score_howto_table[elf32_score_reloc_map[i].elf_reloc_val]; 3698214571Sdim 3699214571Sdim return NULL; 3700214571Sdim} 3701214571Sdim 3702214571Sdimstatic reloc_howto_type * 3703214571Sdimelf32_score_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, 3704214571Sdim const char *r_name) 3705214571Sdim{ 3706214571Sdim unsigned int i; 3707214571Sdim 3708214571Sdim for (i = 0; 3709214571Sdim i < (sizeof (elf32_score_howto_table) 3710214571Sdim / sizeof (elf32_score_howto_table[0])); 3711214571Sdim i++) 3712214571Sdim if (elf32_score_howto_table[i].name != NULL 3713214571Sdim && strcasecmp (elf32_score_howto_table[i].name, r_name) == 0) 3714214571Sdim return &elf32_score_howto_table[i]; 3715214571Sdim 3716214571Sdim return NULL; 3717214571Sdim} 3718214571Sdim 3719214571Sdim/* Create a score elf linker hash table. */ 3720214571Sdim 3721214571Sdimstatic struct bfd_link_hash_table * 3722214571Sdimelf32_score_link_hash_table_create (bfd *abfd) 3723214571Sdim{ 3724214571Sdim struct score_elf_link_hash_table *ret; 3725214571Sdim bfd_size_type amt = sizeof (struct score_elf_link_hash_table); 3726214571Sdim 3727214571Sdim ret = bfd_malloc (amt); 3728214571Sdim if (ret == NULL) 3729214571Sdim return NULL; 3730214571Sdim 3731214571Sdim if (!_bfd_elf_link_hash_table_init (&ret->root, abfd, score_elf_link_hash_newfunc, 3732214571Sdim sizeof (struct score_elf_link_hash_entry))) 3733214571Sdim { 3734214571Sdim free (ret); 3735214571Sdim return NULL; 3736214571Sdim } 3737214571Sdim 3738214571Sdim return &ret->root.root; 3739214571Sdim} 3740214571Sdim 3741214571Sdimstatic bfd_boolean 3742214571Sdimelf32_score_print_private_bfd_data (bfd *abfd, void * ptr) 3743214571Sdim{ 3744214571Sdim FILE *file = (FILE *) ptr; 3745214571Sdim 3746214571Sdim BFD_ASSERT (abfd != NULL && ptr != NULL); 3747214571Sdim 3748214571Sdim /* Print normal ELF private data. */ 3749214571Sdim _bfd_elf_print_private_bfd_data (abfd, ptr); 3750214571Sdim 3751214571Sdim /* xgettext:c-format */ 3752214571Sdim fprintf (file, _("private flags = %lx:"), elf_elfheader (abfd)->e_flags); 3753214571Sdim if (elf_elfheader (abfd)->e_flags & EF_SCORE_PIC) 3754214571Sdim { 3755214571Sdim fprintf (file, _(" [pic]")); 3756214571Sdim } 3757214571Sdim if (elf_elfheader (abfd)->e_flags & EF_SCORE_FIXDEP) 3758214571Sdim { 3759214571Sdim fprintf (file, _(" [fix dep]")); 3760214571Sdim } 3761214571Sdim fputc ('\n', file); 3762214571Sdim 3763214571Sdim return TRUE; 3764214571Sdim} 3765214571Sdim 3766214571Sdimstatic bfd_boolean 3767214571Sdimelf32_score_merge_private_bfd_data (bfd *ibfd, bfd *obfd) 3768214571Sdim{ 3769214571Sdim flagword in_flags; 3770214571Sdim flagword out_flags; 3771214571Sdim 3772214571Sdim if (!_bfd_generic_verify_endian_match (ibfd, obfd)) 3773214571Sdim return FALSE; 3774214571Sdim 3775214571Sdim in_flags = elf_elfheader (ibfd)->e_flags; 3776214571Sdim out_flags = elf_elfheader (obfd)->e_flags; 3777214571Sdim 3778214571Sdim if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour 3779214571Sdim || bfd_get_flavour (obfd) != bfd_target_elf_flavour) 3780214571Sdim return TRUE; 3781214571Sdim 3782214571Sdim in_flags = elf_elfheader (ibfd)->e_flags; 3783214571Sdim out_flags = elf_elfheader (obfd)->e_flags; 3784214571Sdim 3785214571Sdim if (! elf_flags_init (obfd)) 3786214571Sdim { 3787214571Sdim elf_flags_init (obfd) = TRUE; 3788214571Sdim elf_elfheader (obfd)->e_flags = in_flags; 3789214571Sdim 3790214571Sdim if (bfd_get_arch (obfd) == bfd_get_arch (ibfd) 3791214571Sdim && bfd_get_arch_info (obfd)->the_default) 3792214571Sdim { 3793214571Sdim return bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), bfd_get_mach (ibfd)); 3794214571Sdim } 3795214571Sdim 3796214571Sdim return TRUE; 3797214571Sdim } 3798214571Sdim 3799214571Sdim if (((in_flags & EF_SCORE_PIC) != 0) != ((out_flags & EF_SCORE_PIC) != 0)) 3800214571Sdim { 3801214571Sdim (*_bfd_error_handler) (_("%B: warning: linking PIC files with non-PIC files"), ibfd); 3802214571Sdim } 3803214571Sdim 3804214571Sdim /* FIXME: Maybe dependency fix compatibility should be checked here. */ 3805214571Sdim 3806214571Sdim return TRUE; 3807214571Sdim} 3808214571Sdim 3809214571Sdimstatic bfd_boolean 3810214571Sdimelf32_score_new_section_hook (bfd *abfd, asection *sec) 3811214571Sdim{ 3812214571Sdim struct _score_elf_section_data *sdata; 3813214571Sdim bfd_size_type amt = sizeof (*sdata); 3814214571Sdim 3815214571Sdim sdata = bfd_zalloc (abfd, amt); 3816214571Sdim if (sdata == NULL) 3817214571Sdim return FALSE; 3818214571Sdim sec->used_by_bfd = sdata; 3819214571Sdim 3820214571Sdim return _bfd_elf_new_section_hook (abfd, sec); 3821214571Sdim} 3822214571Sdim 3823214571Sdim 3824214571Sdim#define USE_REL 1 3825214571Sdim#define TARGET_LITTLE_SYM bfd_elf32_littlescore_vec 3826214571Sdim#define TARGET_LITTLE_NAME "elf32-littlescore" 3827214571Sdim#define TARGET_BIG_SYM bfd_elf32_bigscore_vec 3828214571Sdim#define TARGET_BIG_NAME "elf32-bigscore" 3829214571Sdim#define ELF_ARCH bfd_arch_score 3830214571Sdim#define ELF_MACHINE_CODE EM_SCORE 3831214571Sdim#define ELF_MAXPAGESIZE 0x8000 3832214571Sdim 3833214571Sdim#define elf_info_to_howto 0 3834214571Sdim#define elf_info_to_howto_rel _bfd_score_info_to_howto 3835214571Sdim#define elf_backend_relocate_section _bfd_score_elf_relocate_section 3836214571Sdim#define elf_backend_check_relocs _bfd_score_elf_check_relocs 3837214571Sdim#define elf_backend_add_symbol_hook _bfd_score_elf_add_symbol_hook 3838214571Sdim#define elf_backend_symbol_processing _bfd_score_elf_symbol_processing 3839214571Sdim#define elf_backend_link_output_symbol_hook \ 3840214571Sdim _bfd_score_elf_link_output_symbol_hook 3841214571Sdim#define elf_backend_section_from_bfd_section \ 3842214571Sdim _bfd_score_elf_section_from_bfd_section 3843214571Sdim#define elf_backend_adjust_dynamic_symbol \ 3844214571Sdim _bfd_score_elf_adjust_dynamic_symbol 3845214571Sdim#define elf_backend_always_size_sections \ 3846214571Sdim _bfd_score_elf_always_size_sections 3847214571Sdim#define elf_backend_size_dynamic_sections \ 3848214571Sdim _bfd_score_elf_size_dynamic_sections 3849214571Sdim#define elf_backend_omit_section_dynsym \ 3850214571Sdim ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true) 3851214571Sdim#define elf_backend_create_dynamic_sections \ 3852214571Sdim _bfd_score_elf_create_dynamic_sections 3853214571Sdim#define elf_backend_finish_dynamic_symbol \ 3854214571Sdim _bfd_score_elf_finish_dynamic_symbol 3855214571Sdim#define elf_backend_finish_dynamic_sections \ 3856214571Sdim _bfd_score_elf_finish_dynamic_sections 3857214571Sdim#define elf_backend_fake_sections _bfd_score_elf_fake_sections 3858214571Sdim#define elf_backend_section_processing _bfd_score_elf_section_processing 3859214571Sdim#define elf_backend_write_section _bfd_score_elf_write_section 3860214571Sdim#define elf_backend_copy_indirect_symbol _bfd_score_elf_copy_indirect_symbol 3861214571Sdim#define elf_backend_hide_symbol _bfd_score_elf_hide_symbol 3862214571Sdim#define elf_backend_discard_info _bfd_score_elf_discard_info 3863214571Sdim#define elf_backend_ignore_discarded_relocs \ 3864214571Sdim _bfd_score_elf_ignore_discarded_relocs 3865214571Sdim#define elf_backend_gc_mark_hook _bfd_score_elf_gc_mark_hook 3866214571Sdim#define elf_backend_grok_prstatus _bfd_score_elf_grok_prstatus 3867214571Sdim#define elf_backend_grok_psinfo _bfd_score_elf_grok_psinfo 3868214571Sdim#define elf_backend_can_gc_sections 1 3869214571Sdim#define elf_backend_want_plt_sym 0 3870214571Sdim#define elf_backend_got_header_size (4 * SCORE_RESERVED_GOTNO) 3871214571Sdim#define elf_backend_plt_header_size 0 3872214571Sdim#define elf_backend_collect TRUE 3873214571Sdim#define elf_backend_type_change_ok TRUE 3874214571Sdim 3875214571Sdim#define bfd_elf32_bfd_reloc_type_lookup elf32_score_reloc_type_lookup 3876214571Sdim#define bfd_elf32_bfd_reloc_name_lookup \ 3877214571Sdim elf32_score_reloc_name_lookup 3878214571Sdim#define bfd_elf32_bfd_link_hash_table_create elf32_score_link_hash_table_create 3879214571Sdim#define bfd_elf32_bfd_print_private_bfd_data elf32_score_print_private_bfd_data 3880214571Sdim#define bfd_elf32_bfd_merge_private_bfd_data elf32_score_merge_private_bfd_data 3881214571Sdim#define bfd_elf32_new_section_hook elf32_score_new_section_hook 3882214571Sdim 3883214571Sdim#include "elf32-target.h" 3884