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