1/* ARC-specific support for 32-bit ELF 2 Copyright (C) 1994-2017 Free Software Foundation, Inc. 3 Contributed by Cupertino Miranda (cmiranda@synopsys.com). 4 5 This file is part of BFD, the Binary File Descriptor library. 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program; if not, write to the Free Software 19 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 20 MA 02110-1301, USA. */ 21 22#ifndef ARC_GOT_H 23#define ARC_GOT_H 24 25enum tls_type_e 26{ 27 GOT_UNKNOWN = 0, 28 GOT_NORMAL, 29 GOT_TLS_GD, 30 GOT_TLS_IE, 31 GOT_TLS_LE 32}; 33 34enum tls_got_entries 35{ 36 TLS_GOT_NONE = 0, 37 TLS_GOT_MOD, 38 TLS_GOT_OFF, 39 TLS_GOT_MOD_AND_OFF 40}; 41 42struct got_entry 43{ 44 struct got_entry *next; 45 enum tls_type_e type; 46 bfd_vma offset; 47 bfd_boolean processed; 48 bfd_boolean created_dyn_relocation; 49 enum tls_got_entries existing_entries; 50}; 51 52static struct got_entry ** 53arc_get_local_got_ents (bfd * abfd) 54{ 55 static struct got_entry **local_got_ents = NULL; 56 57 if (local_got_ents == NULL) 58 { 59 size_t size; 60 Elf_Internal_Shdr *symtab_hdr = &((elf_tdata (abfd))->symtab_hdr); 61 62 size = symtab_hdr->sh_info * sizeof (bfd_vma); 63 local_got_ents = (struct got_entry **) 64 bfd_alloc (abfd, sizeof (struct got_entry *) * size); 65 if (local_got_ents == NULL) 66 return FALSE; 67 68 memset (local_got_ents, 0, sizeof (struct got_entry *) * size); 69 elf_local_got_ents (abfd) = local_got_ents; 70 } 71 72 return local_got_ents; 73} 74 75static struct got_entry * 76got_entry_for_type (struct got_entry **list, 77 enum tls_type_e type) 78{ 79 struct got_entry **p = list; 80 81 while (*p != NULL) 82 { 83 if ((*p)->type == type) 84 return *p; 85 p = &((*p)->next); 86 } 87 return NULL; 88} 89 90static void 91new_got_entry_to_list (struct got_entry **list, 92 enum tls_type_e type, 93 bfd_vma offset, 94 enum tls_got_entries existing_entries) 95{ 96 /* Find list end. Avoid having multiple entries of the same 97 type. */ 98 struct got_entry **p = list; 99 struct got_entry *entry; 100 101 while (*p != NULL) 102 { 103 if ((*p)->type == type) 104 return; 105 p = &((*p)->next); 106 } 107 108 entry = (struct got_entry *) xmalloc (sizeof (struct got_entry)); 109 110 entry->type = type; 111 entry->offset = offset; 112 entry->next = NULL; 113 entry->processed = FALSE; 114 entry->created_dyn_relocation = FALSE; 115 entry->existing_entries = existing_entries; 116 117 ARC_DEBUG ("New GOT got entry added to list: " 118 "type: %d, offset: %ld, existing_entries: %d\n", 119 type, (long) offset, existing_entries); 120 121 /* Add the entry to the end of the list. */ 122 *p = entry; 123} 124 125static enum tls_type_e 126tls_type_for_reloc (reloc_howto_type *howto) 127{ 128 enum tls_type_e ret = GOT_UNKNOWN; 129 130 if (is_reloc_for_GOT (howto)) 131 return GOT_NORMAL; 132 133 switch (howto->type) 134 { 135 case R_ARC_TLS_GD_GOT: 136 ret = GOT_TLS_GD; 137 break; 138 case R_ARC_TLS_IE_GOT: 139 ret = GOT_TLS_IE; 140 break; 141 case R_ARC_TLS_LE_32: 142 ret = GOT_TLS_LE; 143 break; 144 default: 145 ret = GOT_UNKNOWN; 146 break; 147 } 148 149 return ret; 150}; 151 152static struct got_entry ** 153get_got_entry_list_for_symbol (bfd *abfd, 154 unsigned long r_symndx, 155 struct elf_link_hash_entry *h) 156{ 157 if (h != NULL) 158 { 159 return &h->got.glist; 160 } 161 else 162 { 163 struct got_entry **local_got_ents 164 = arc_get_local_got_ents (abfd); 165 return &local_got_ents[r_symndx]; 166 } 167} 168 169 170static enum tls_type_e 171arc_got_entry_type_for_reloc (reloc_howto_type *howto) 172{ 173 enum tls_type_e type = GOT_UNKNOWN; 174 175 if (is_reloc_for_GOT (howto)) 176 return GOT_NORMAL; 177 178 if (is_reloc_for_TLS (howto)) 179 { 180 switch (howto->type) 181 { 182 case R_ARC_TLS_GD_GOT: 183 type = GOT_TLS_GD; 184 break; 185 case R_ARC_TLS_IE_GOT: 186 type = GOT_TLS_IE; 187 break; 188 default: 189 break; 190 } 191 } 192 return type; 193} 194 195#define ADD_SYMBOL_REF_SEC_AND_RELOC(SECNAME, COND_FOR_RELOC, H) \ 196 htab->s##SECNAME->size; \ 197 { \ 198 if (COND_FOR_RELOC) \ 199 { \ 200 htab->srel##SECNAME->size += sizeof (Elf32_External_Rela); \ 201 ARC_DEBUG ("arc_info: Added reloc space in " \ 202 #SECNAME " section at " __FILE__ \ 203 ":%d for symbol %s\n", \ 204 __LINE__, name_for_global_symbol (H)); \ 205 } \ 206 if (H) \ 207 if (h->dynindx == -1 && !h->forced_local) \ 208 if (! bfd_elf_link_record_dynamic_symbol (info, H)) \ 209 return FALSE; \ 210 htab->s##SECNAME->size += 4; \ 211 } \ 212 213static bfd_boolean 214arc_fill_got_info_for_reloc (enum tls_type_e type, 215 struct got_entry **list, 216 struct bfd_link_info * info, 217 struct elf_link_hash_entry *h) 218{ 219 struct elf_link_hash_table *htab = elf_hash_table (info); 220 221 if (got_entry_for_type (list, type) != NULL) 222 return TRUE; 223 224 switch (type) 225 { 226 case GOT_NORMAL: 227 { 228 bfd_vma offset 229 = ADD_SYMBOL_REF_SEC_AND_RELOC (got, bfd_link_pic (info) 230 || h != NULL, h); 231 new_got_entry_to_list (list, type, offset, TLS_GOT_NONE); 232 } 233 break; 234 235 236 case GOT_TLS_GD: 237 { 238 bfd_vma offset 239 = ADD_SYMBOL_REF_SEC_AND_RELOC (got, TRUE, h); 240 bfd_vma ATTRIBUTE_UNUSED notneeded 241 = ADD_SYMBOL_REF_SEC_AND_RELOC (got, TRUE, h); 242 new_got_entry_to_list (list, type, offset, TLS_GOT_MOD_AND_OFF); 243 } 244 break; 245 case GOT_TLS_IE: 246 case GOT_TLS_LE: 247 { 248 bfd_vma offset 249 = ADD_SYMBOL_REF_SEC_AND_RELOC (got, TRUE, h); 250 new_got_entry_to_list (list, type, offset, TLS_GOT_OFF); 251 } 252 break; 253 254 default: 255 return FALSE; 256 break; 257 } 258 return TRUE; 259} 260 261 262static bfd_vma 263relocate_fix_got_relocs_for_got_info (struct got_entry ** list_p, 264 enum tls_type_e type, 265 struct bfd_link_info * info, 266 bfd * output_bfd, 267 unsigned long r_symndx, 268 Elf_Internal_Sym * local_syms, 269 asection ** local_sections, 270 struct elf_link_hash_entry * h, 271 struct arc_relocation_data * reloc_data) 272{ 273 struct elf_link_hash_table *htab = elf_hash_table (info); 274 struct got_entry *entry = NULL; 275 276 if (list_p == NULL || type == GOT_UNKNOWN || type == GOT_TLS_LE) 277 return 0; 278 279 entry = got_entry_for_type (list_p, type); 280 BFD_ASSERT (entry); 281 282 if (h == NULL 283 || (! elf_hash_table (info)->dynamic_sections_created 284 || (bfd_link_pic (info) 285 && SYMBOL_REFERENCES_LOCAL (info, h)))) 286 { 287 const char ATTRIBUTE_UNUSED *symbol_name; 288 static const char local_name[] = "(local)"; 289 asection *tls_sec = NULL; 290 bfd_vma sym_value = 0; 291 292 if (h != NULL) 293 { 294 // TODO: This should not be here. 295 reloc_data->sym_value = h->root.u.def.value; 296 reloc_data->sym_section = h->root.u.def.section; 297 298 sym_value = h->root.u.def.value 299 + h->root.u.def.section->output_section->vma 300 + h->root.u.def.section->output_offset; 301 302 tls_sec = elf_hash_table (info)->tls_sec; 303 304 symbol_name = h->root.root.string; 305 } 306 else 307 { 308 Elf_Internal_Sym *sym = local_syms + r_symndx; 309 asection *sec = local_sections[r_symndx]; 310 311 sym_value = sym->st_value 312 + sec->output_section->vma 313 + sec->output_offset; 314 315 tls_sec = elf_hash_table (info)->tls_sec; 316 317 symbol_name = local_name; 318 } 319 320 321 if (entry && entry->processed == FALSE) 322 { 323 switch (entry->type) 324 { 325 case GOT_TLS_GD: 326 { 327 BFD_ASSERT (tls_sec && tls_sec->output_section); 328 bfd_vma sec_vma = tls_sec->output_section->vma; 329 330 bfd_put_32 (output_bfd, 331 sym_value - sec_vma, 332 htab->sgot->contents + entry->offset 333 + (entry->existing_entries == TLS_GOT_MOD_AND_OFF 334 ? 4 : 0)); 335 336 ARC_DEBUG ("arc_info: FIXED -> %s value = %#lx " 337 "@ %lx, for symbol %s\n", 338 (entry->type == GOT_TLS_GD ? "GOT_TLS_GD" : 339 "GOT_TLS_IE"), 340 (long) (sym_value - sec_vma), 341 (long) (htab->sgot->output_section->vma 342 + htab->sgot->output_offset->vma 343 + entry->offset 344 + (entry->existing_entries == TLS_GOT_MOD_AND_OFF 345 ? 4 : 0)), 346 symbol_name); 347 } 348 break; 349 350 case GOT_TLS_IE: 351 { 352 BFD_ASSERT (tls_sec && tls_sec->output_section); 353 bfd_vma ATTRIBUTE_UNUSED sec_vma 354 = tls_sec->output_section->vma; 355 356 bfd_put_32 (output_bfd, 357 sym_value - sec_vma, 358 htab->sgot->contents + entry->offset 359 + (entry->existing_entries == TLS_GOT_MOD_AND_OFF 360 ? 4 : 0)); 361 362 ARC_DEBUG ("arc_info: FIXED -> %s value = %#lx " 363 "@ %p, for symbol %s\n", 364 (entry->type == GOT_TLS_GD ? "GOT_TLS_GD" : 365 "GOT_TLS_IE"), 366 (long) (sym_value - sec_vma), 367 (long) (htab->sgot->output_section->vma 368 + htab->sgot->output_offset->vma 369 + entry->offset 370 + (entry->existing_entries == TLS_GOT_MOD_AND_OFF 371 ? 4 : 0)), 372 symbol_name); 373 } 374 break; 375 376 case GOT_NORMAL: 377 { 378 bfd_vma sec_vma 379 = reloc_data->sym_section->output_section->vma 380 + reloc_data->sym_section->output_offset; 381 382 if (h != NULL 383 && h->root.type == bfd_link_hash_undefweak) 384 ARC_DEBUG ("arc_info: PATCHED: NOT_PATCHED " 385 "@ %#08lx for sym %s in got offset %#lx " 386 "(is undefweak)\n", 387 (long) (htab->sgot->output_section->vma 388 + htab->sgot->output_offset 389 + entry->offset), 390 symbol_name, 391 (long) entry->offset); 392 else 393 { 394 bfd_put_32 (output_bfd, 395 reloc_data->sym_value + sec_vma, 396 htab->sgot->contents + entry->offset); 397 ARC_DEBUG ("arc_info: PATCHED: %#08lx " 398 "@ %#08lx for sym %s in got offset %#lx\n", 399 (long) (reloc_data->sym_value + sec_vma), 400 (long) (htab->sgot->output_section->vma 401 + htab->sgot->output_offset + entry->offset), 402 symbol_name, 403 (long) entry->offset); 404 } 405 } 406 break; 407 default: 408 BFD_ASSERT (0); 409 break; 410 } 411 entry->processed = TRUE; 412 } 413 } 414 415 return entry->offset; 416} 417 418static void 419create_got_dynrelocs_for_single_entry (struct got_entry *list, 420 bfd *output_bfd, 421 struct bfd_link_info * info, 422 struct elf_link_hash_entry *h) 423{ 424 if (list == NULL) 425 return; 426 427 bfd_vma got_offset = list->offset; 428 429 if (list->type == GOT_NORMAL 430 && list->created_dyn_relocation == FALSE) 431 { 432 if (bfd_link_pic (info) 433 && h != NULL 434 && (info->symbolic || h->dynindx == -1) 435 && h->def_regular) 436 { 437 ADD_RELA (output_bfd, got, got_offset, 0, R_ARC_RELATIVE, 0); 438 } 439 /* Do not fully understand the side effects of this condition. 440 The relocation space might still being reserved. Perhaps 441 I should clear its value. */ 442 else if (h != NULL && h->dynindx != -1) 443 { 444 ADD_RELA (output_bfd, got, got_offset, h->dynindx, R_ARC_GLOB_DAT, 0); 445 } 446 list->created_dyn_relocation = TRUE; 447 } 448 else if (list->existing_entries != TLS_GOT_NONE 449 && list->created_dyn_relocation == FALSE) 450 { 451 /* TODO TLS: This is not called for local symbols. 452 In order to correctly implement TLS, this should also 453 be called for all local symbols with tls got entries. 454 Should be moved to relocate_section in order to make it 455 work for local symbols. */ 456 struct elf_link_hash_table *htab = elf_hash_table (info); 457 enum tls_got_entries e = list->existing_entries; 458 459 BFD_ASSERT (list->type != GOT_TLS_GD 460 || list->existing_entries == TLS_GOT_MOD_AND_OFF); 461 462 bfd_vma dynindx = (h == NULL || h->dynindx == -1) ? 0 : h->dynindx; 463 464 if (e == TLS_GOT_MOD_AND_OFF || e == TLS_GOT_MOD) 465 { 466 ADD_RELA (output_bfd, got, got_offset, dynindx, 467 R_ARC_TLS_DTPMOD, 0); 468 ARC_DEBUG ("arc_info: TLS_DYNRELOC: type = %d, \ 469GOT_OFFSET = %#lx, GOT_VMA = %#lx, INDEX = %ld, ADDEND = 0x0\n", 470 list->type, 471 (long) got_offset, 472 (long) (htab->sgot->output_section->vma 473 + htab->sgot->output_offset + got_offset), 474 (long) dynindx); 475 } 476 477 if (e == TLS_GOT_MOD_AND_OFF || e == TLS_GOT_OFF) 478 { 479 bfd_vma addend = 0; 480 if (list->type == GOT_TLS_IE) 481 addend = bfd_get_32 (output_bfd, 482 htab->sgot->contents + got_offset); 483 484 ADD_RELA (output_bfd, got, 485 got_offset + (e == TLS_GOT_MOD_AND_OFF ? 4 : 0), 486 dynindx, 487 (list->type == GOT_TLS_IE ? R_ARC_TLS_TPOFF 488 : R_ARC_TLS_DTPOFF), 489 addend); 490 491 ARC_DEBUG ("arc_info: TLS_DYNRELOC: type = %d, \ 492GOT_OFFSET = %#lx, GOT_VMA = %#lx, INDEX = %ld, ADDEND = %#lx\n", 493 list->type, 494 (long) got_offset, 495 (long) (htab->sgot->output_section->vma 496 + htab->sgot->output_offset + got_offset), 497 (long) dynindx, (long) addend); 498 } 499 list->created_dyn_relocation = TRUE; 500 } 501} 502 503static void 504create_got_dynrelocs_for_got_info (struct got_entry **list_p, 505 bfd *output_bfd, 506 struct bfd_link_info * info, 507 struct elf_link_hash_entry *h) 508{ 509 if (list_p == NULL) 510 return; 511 512 struct got_entry *list = *list_p; 513 /* Traverse the list of got entries for this symbol. */ 514 while (list) 515 { 516 create_got_dynrelocs_for_single_entry (list, output_bfd, info, h); 517 list = list->next; 518 } 519} 520 521#undef ADD_SYMBOL_REF_SEC_AND_RELOC 522 523#endif /* ARC_GOT_H */ 524