11573Srgrimes/* ARC-specific support for 32-bit ELF 21573Srgrimes Copyright (C) 1994-2020 Free Software Foundation, Inc. 31573Srgrimes Contributed by Cupertino Miranda (cmiranda@synopsys.com). 41573Srgrimes 5227753Stheraven This file is part of BFD, the Binary File Descriptor library. 6227753Stheraven 7227753Stheraven This program is free software; you can redistribute it and/or modify 8227753Stheraven it under the terms of the GNU General Public License as published by 9227753Stheraven the Free Software Foundation; either version 3 of the License, or 101573Srgrimes (at your option) any later version. 111573Srgrimes 121573Srgrimes This program is distributed in the hope that it will be useful, 131573Srgrimes but WITHOUT ANY WARRANTY; without even the implied warranty of 141573Srgrimes MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 151573Srgrimes GNU General Public License for more details. 161573Srgrimes 171573Srgrimes You should have received a copy of the GNU General Public License 181573Srgrimes along with this program; if not, write to the Free Software 191573Srgrimes Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 201573Srgrimes MA 02110-1301, USA. */ 211573Srgrimes 221573Srgrimes#ifndef ARC_GOT_H 231573Srgrimes#define ARC_GOT_H 241573Srgrimes 251573Srgrimes#define TCB_SIZE (8) 261573Srgrimes 271573Srgrimes#define align_power(addr, align) \ 281573Srgrimes (((addr) + ((bfd_vma) 1 << (align)) - 1) & (-((bfd_vma) 1 << (align)))) 291573Srgrimes 301573Srgrimesenum tls_type_e 311573Srgrimes{ 321573Srgrimes GOT_UNKNOWN = 0, 331573Srgrimes GOT_NORMAL, 341573Srgrimes GOT_TLS_GD, 351573Srgrimes GOT_TLS_IE, 361573Srgrimes GOT_TLS_LE 371573Srgrimes}; 3892986Sobrien 3992986Sobrienenum tls_got_entries 401573Srgrimes{ 411573Srgrimes TLS_GOT_NONE = 0, 421573Srgrimes TLS_GOT_MOD, 431573Srgrimes TLS_GOT_OFF, 441573Srgrimes TLS_GOT_MOD_AND_OFF 45227753Stheraven}; 461573Srgrimes 471573Srgrimesstruct got_entry 481573Srgrimes{ 491573Srgrimes struct got_entry *next; 5082975Sache enum tls_type_e type; 511573Srgrimes bfd_vma offset; 521573Srgrimes bfd_boolean processed; 531573Srgrimes bfd_boolean created_dyn_relocation; 54227753Stheraven enum tls_got_entries existing_entries; 551573Srgrimes}; 5687016Sache 5787016Sache/* Return the local got list, if not defined, create an empty one. */ 5887494Sache 5987016Sachestatic struct got_entry ** 6087494Sachearc_get_local_got_ents (bfd * abfd) 61227753Stheraven{ 621573Srgrimes if (elf_local_got_ents (abfd) == NULL) 631573Srgrimes { 641573Srgrimes bfd_size_type amt = (elf_tdata (abfd)->symtab_hdr.sh_info 651573Srgrimes * sizeof (*elf_local_got_ents (abfd))); 6682975Sache elf_local_got_ents (abfd) = bfd_zmalloc (amt); 671573Srgrimes if (elf_local_got_ents (abfd) == NULL) 681573Srgrimes { 69227753Stheraven _bfd_error_handler (_("%pB: cannot allocate memory for local " 701573Srgrimes "GOT entries"), abfd); 711573Srgrimes bfd_set_error (bfd_error_bad_value); 721573Srgrimes return NULL; 7382975Sache } 7482975Sache } 7582975Sache 7682975Sache return elf_local_got_ents (abfd); 7782975Sache} 781573Srgrimes 79140536Sachestatic struct got_entry * 80140577Sachegot_entry_for_type (struct got_entry **list, 81140577Sache enum tls_type_e type) 82140577Sache{ 831573Srgrimes struct got_entry **p = list; 841573Srgrimes 851573Srgrimes while (*p != NULL) 861573Srgrimes { 871573Srgrimes if ((*p)->type == type) 881573Srgrimes return *p; 8982982Sache p = &((*p)->next); 9087023Sfenner } 9182975Sache return NULL; 9282975Sache} 9382975Sache 9482975Sachestatic void 9582982Sachenew_got_entry_to_list (struct got_entry **list, 9687494Sache enum tls_type_e type, 9787494Sache bfd_vma offset, 9887494Sache enum tls_got_entries existing_entries) 9987494Sache{ 10087494Sache /* Find list end. Avoid having multiple entries of the same 10187494Sache type. */ 1021573Srgrimes struct got_entry **p = list; 1031573Srgrimes struct got_entry *entry; 10487494Sache 1051573Srgrimes while (*p != NULL) 10687494Sache { 1071573Srgrimes if ((*p)->type == type) 1081573Srgrimes return; 1091573Srgrimes p = &((*p)->next); 1101573Srgrimes } 11187494Sache 1121573Srgrimes entry = (struct got_entry *) xmalloc (sizeof (struct got_entry)); 1131573Srgrimes 1141573Srgrimes entry->type = type; 1151573Srgrimes entry->offset = offset; 1161573Srgrimes entry->next = NULL; 11782975Sache entry->processed = FALSE; 11882975Sache entry->created_dyn_relocation = FALSE; 11982975Sache entry->existing_entries = existing_entries; 1201573Srgrimes 1211573Srgrimes ARC_DEBUG ("New GOT got entry added to list: " 12282975Sache "type: %d, offset: %ld, existing_entries: %d\n", 1231573Srgrimes type, (long) offset, existing_entries); 1241573Srgrimes 1251573Srgrimes /* Add the entry to the end of the list. */ 126227753Stheraven *p = entry; 127227753Stheraven} 128227753Stheraven 129227753Stheravenstatic enum tls_type_e 130227753Stheraventls_type_for_reloc (reloc_howto_type *howto) 131{ 132 enum tls_type_e ret = GOT_UNKNOWN; 133 134 if (is_reloc_for_GOT (howto)) 135 return GOT_NORMAL; 136 137 switch (howto->type) 138 { 139 case R_ARC_TLS_GD_GOT: 140 ret = GOT_TLS_GD; 141 break; 142 case R_ARC_TLS_IE_GOT: 143 ret = GOT_TLS_IE; 144 break; 145 case R_ARC_TLS_LE_32: 146 ret = GOT_TLS_LE; 147 break; 148 default: 149 ret = GOT_UNKNOWN; 150 break; 151 } 152 153 return ret; 154}; 155 156static struct got_entry ** 157get_got_entry_list_for_symbol (bfd *abfd, 158 unsigned long r_symndx, 159 struct elf_link_hash_entry *h) 160{ 161 struct elf_arc_link_hash_entry *h1 = 162 ((struct elf_arc_link_hash_entry *) h); 163 if (h1 != NULL) 164 { 165 return &h1->got_ents; 166 } 167 else 168 { 169 return arc_get_local_got_ents (abfd) + r_symndx; 170 } 171} 172 173 174static enum tls_type_e 175arc_got_entry_type_for_reloc (reloc_howto_type *howto) 176{ 177 enum tls_type_e type = GOT_UNKNOWN; 178 179 if (is_reloc_for_GOT (howto)) 180 return GOT_NORMAL; 181 182 if (is_reloc_for_TLS (howto)) 183 { 184 switch (howto->type) 185 { 186 case R_ARC_TLS_GD_GOT: 187 type = GOT_TLS_GD; 188 break; 189 case R_ARC_TLS_IE_GOT: 190 type = GOT_TLS_IE; 191 break; 192 default: 193 break; 194 } 195 } 196 return type; 197} 198 199#define ADD_SYMBOL_REF_SEC_AND_RELOC(SECNAME, COND_FOR_RELOC, H) \ 200 htab->s##SECNAME->size; \ 201 { \ 202 if (COND_FOR_RELOC) \ 203 { \ 204 htab->srel##SECNAME->size += sizeof (Elf32_External_Rela); \ 205 ARC_DEBUG ("arc_info: Added reloc space in " \ 206 #SECNAME " section at " __FILE__ \ 207 ":%d for symbol %s\n", \ 208 __LINE__, name_for_global_symbol (H)); \ 209 } \ 210 if (H) \ 211 if (H->dynindx == -1 && !H->forced_local) \ 212 if (! bfd_elf_link_record_dynamic_symbol (info, H)) \ 213 return FALSE; \ 214 htab->s##SECNAME->size += 4; \ 215 } \ 216 217static bfd_boolean 218arc_fill_got_info_for_reloc (enum tls_type_e type, 219 struct got_entry **list, 220 struct bfd_link_info * info, 221 struct elf_link_hash_entry *h) 222{ 223 struct elf_link_hash_table *htab = elf_hash_table (info); 224 225 if (got_entry_for_type (list, type) != NULL) 226 return TRUE; 227 228 switch (type) 229 { 230 case GOT_NORMAL: 231 { 232 bfd_vma offset 233 = ADD_SYMBOL_REF_SEC_AND_RELOC (got, bfd_link_pic (info) 234 || h != NULL, h); 235 new_got_entry_to_list (list, type, offset, TLS_GOT_NONE); 236 } 237 break; 238 239 240 case GOT_TLS_GD: 241 { 242 bfd_vma offset 243 = ADD_SYMBOL_REF_SEC_AND_RELOC (got, TRUE, h); 244 bfd_vma ATTRIBUTE_UNUSED notneeded 245 = ADD_SYMBOL_REF_SEC_AND_RELOC (got, TRUE, h); 246 new_got_entry_to_list (list, type, offset, TLS_GOT_MOD_AND_OFF); 247 } 248 break; 249 case GOT_TLS_IE: 250 case GOT_TLS_LE: 251 { 252 bfd_vma offset 253 = ADD_SYMBOL_REF_SEC_AND_RELOC (got, TRUE, h); 254 new_got_entry_to_list (list, type, offset, TLS_GOT_OFF); 255 } 256 break; 257 258 default: 259 return FALSE; 260 break; 261 } 262 return TRUE; 263} 264 265 266static bfd_vma 267relocate_fix_got_relocs_for_got_info (struct got_entry ** list_p, 268 enum tls_type_e type, 269 struct bfd_link_info * info, 270 bfd * output_bfd, 271 unsigned long r_symndx, 272 Elf_Internal_Sym * local_syms, 273 asection ** local_sections, 274 struct elf_link_hash_entry * h, 275 struct arc_relocation_data * reloc_data) 276{ 277 struct elf_link_hash_table *htab = elf_hash_table (info); 278 struct got_entry *entry = NULL; 279 280 if (list_p == NULL || type == GOT_UNKNOWN || type == GOT_TLS_LE) 281 return 0; 282 283 entry = got_entry_for_type (list_p, type); 284 BFD_ASSERT (entry); 285 286 if (h == NULL 287 || h->forced_local == TRUE 288 || (! elf_hash_table (info)->dynamic_sections_created 289 || (bfd_link_pic (info) 290 && SYMBOL_REFERENCES_LOCAL (info, h)))) 291 { 292 const char ATTRIBUTE_UNUSED *symbol_name; 293 static const char local_name[] = "(local)"; 294 asection *tls_sec = NULL; 295 bfd_vma sym_value = 0; 296 297 if (h != NULL) 298 { 299 /* TODO: This should not be here. */ 300 reloc_data->sym_value = h->root.u.def.value; 301 reloc_data->sym_section = h->root.u.def.section; 302 303 sym_value = h->root.u.def.value 304 + h->root.u.def.section->output_section->vma 305 + h->root.u.def.section->output_offset; 306 307 tls_sec = elf_hash_table (info)->tls_sec; 308 309 symbol_name = h->root.root.string; 310 } 311 else 312 { 313 Elf_Internal_Sym *sym = local_syms + r_symndx; 314 asection *sec = local_sections[r_symndx]; 315 316 sym_value = sym->st_value 317 + sec->output_section->vma 318 + sec->output_offset; 319 320 tls_sec = elf_hash_table (info)->tls_sec; 321 322 symbol_name = local_name; 323 } 324 325 326 if (entry && !entry->processed) 327 { 328 switch (entry->type) 329 { 330 case GOT_TLS_GD: 331 { 332 BFD_ASSERT (tls_sec && tls_sec->output_section); 333 bfd_vma sec_vma = tls_sec->output_section->vma; 334 335 if (h == NULL || h->forced_local 336 || !elf_hash_table (info)->dynamic_sections_created) 337 { 338 bfd_put_32 (output_bfd, 339 sym_value - sec_vma 340 + (elf_hash_table (info)->dynamic_sections_created 341 ? 0 342 : (align_power (0, 343 tls_sec->alignment_power))), 344 htab->sgot->contents + entry->offset 345 + (entry->existing_entries == TLS_GOT_MOD_AND_OFF 346 ? 4 : 0)); 347 348 ARC_DEBUG ("arc_info: FIXED -> %s value = %#lx " 349 "@ %lx, for symbol %s\n", 350 (entry->type == GOT_TLS_GD ? "GOT_TLS_GD" : 351 "GOT_TLS_IE"), 352 (long) (sym_value - sec_vma), 353 (long) (htab->sgot->output_section->vma 354 + htab->sgot->output_offset 355 + entry->offset 356 + (entry->existing_entries == TLS_GOT_MOD_AND_OFF 357 ? 4 : 0)), 358 symbol_name); 359 } 360 } 361 break; 362 363 case GOT_TLS_IE: 364 { 365 BFD_ASSERT (tls_sec && tls_sec->output_section); 366 bfd_vma ATTRIBUTE_UNUSED sec_vma 367 = tls_sec->output_section->vma; 368 369 bfd_put_32 (output_bfd, 370 sym_value - sec_vma 371 + (elf_hash_table (info)->dynamic_sections_created 372 ? 0 373 : (align_power (TCB_SIZE, 374 tls_sec->alignment_power))), 375 htab->sgot->contents + entry->offset 376 + (entry->existing_entries == TLS_GOT_MOD_AND_OFF 377 ? 4 : 0)); 378 379 ARC_DEBUG ("arc_info: FIXED -> %s value = %#lx " 380 "@ %p, for symbol %s\n", 381 (entry->type == GOT_TLS_GD ? "GOT_TLS_GD" : 382 "GOT_TLS_IE"), 383 (long) (sym_value - sec_vma), 384 (long) (htab->sgot->output_section->vma 385 + htab->sgot->output_offset 386 + entry->offset 387 + (entry->existing_entries == TLS_GOT_MOD_AND_OFF 388 ? 4 : 0)), 389 symbol_name); 390 } 391 break; 392 393 case GOT_NORMAL: 394 { 395 bfd_vma sec_vma 396 = reloc_data->sym_section->output_section->vma 397 + reloc_data->sym_section->output_offset; 398 399 if (h != NULL 400 && h->root.type == bfd_link_hash_undefweak) 401 ARC_DEBUG ("arc_info: PATCHED: NOT_PATCHED " 402 "@ %#08lx for sym %s in got offset %#lx " 403 "(is undefweak)\n", 404 (long) (htab->sgot->output_section->vma 405 + htab->sgot->output_offset 406 + entry->offset), 407 symbol_name, 408 (long) entry->offset); 409 else 410 { 411 bfd_put_32 (output_bfd, 412 reloc_data->sym_value + sec_vma, 413 htab->sgot->contents + entry->offset); 414 ARC_DEBUG ("arc_info: PATCHED: %#08lx " 415 "@ %#08lx for sym %s in got offset %#lx\n", 416 (long) (reloc_data->sym_value + sec_vma), 417 (long) (htab->sgot->output_section->vma 418 + htab->sgot->output_offset + entry->offset), 419 symbol_name, 420 (long) entry->offset); 421 } 422 } 423 break; 424 default: 425 BFD_ASSERT (0); 426 break; 427 } 428 entry->processed = TRUE; 429 } 430 } 431 432 return entry->offset; 433} 434 435static void 436create_got_dynrelocs_for_single_entry (struct got_entry *list, 437 bfd *output_bfd, 438 struct bfd_link_info * info, 439 struct elf_link_hash_entry *h) 440{ 441 if (list == NULL) 442 return; 443 444 bfd_vma got_offset = list->offset; 445 446 if (list->type == GOT_NORMAL 447 && !list->created_dyn_relocation) 448 { 449 if (bfd_link_pic (info) 450 && h != NULL 451 && (info->symbolic || h->dynindx == -1) 452 && h->def_regular) 453 { 454 ADD_RELA (output_bfd, got, got_offset, 0, R_ARC_RELATIVE, 0); 455 } 456 /* Do not fully understand the side effects of this condition. 457 The relocation space might still being reserved. Perhaps 458 I should clear its value. */ 459 else if (h != NULL && h->dynindx != -1) 460 { 461 ADD_RELA (output_bfd, got, got_offset, h->dynindx, R_ARC_GLOB_DAT, 0); 462 } 463 list->created_dyn_relocation = TRUE; 464 } 465 else if (list->existing_entries != TLS_GOT_NONE 466 && !list->created_dyn_relocation) 467 { 468 /* TODO TLS: This is not called for local symbols. 469 In order to correctly implement TLS, this should also 470 be called for all local symbols with tls got entries. 471 Should be moved to relocate_section in order to make it 472 work for local symbols. */ 473 struct elf_link_hash_table *htab = elf_hash_table (info); 474 enum tls_got_entries e = list->existing_entries; 475 476 BFD_ASSERT (list->type != GOT_TLS_GD 477 || list->existing_entries == TLS_GOT_MOD_AND_OFF); 478 479 bfd_vma dynindx = (h == NULL || h->dynindx == -1) ? 0 : h->dynindx; 480 481 if (e == TLS_GOT_MOD_AND_OFF || e == TLS_GOT_MOD) 482 { 483 ADD_RELA (output_bfd, got, got_offset, dynindx, 484 R_ARC_TLS_DTPMOD, 0); 485 ARC_DEBUG ("arc_info: TLS_DYNRELOC: type = %d, \ 486GOT_OFFSET = %#lx, GOT_VMA = %#lx, INDEX = %ld, ADDEND = 0x0\n", 487 list->type, 488 (long) got_offset, 489 (long) (htab->sgot->output_section->vma 490 + htab->sgot->output_offset + got_offset), 491 (long) dynindx); 492 } 493 494 if (e == TLS_GOT_MOD_AND_OFF || e == TLS_GOT_OFF) 495 { 496 bfd_vma addend = 0; 497 if (list->type == GOT_TLS_IE) 498 { 499 addend = bfd_get_32 (output_bfd, 500 htab->sgot->contents + got_offset); 501 } 502 503 ADD_RELA (output_bfd, got, 504 got_offset + (e == TLS_GOT_MOD_AND_OFF ? 4 : 0), 505 dynindx, 506 (list->type == GOT_TLS_IE ? R_ARC_TLS_TPOFF 507 : R_ARC_TLS_DTPOFF), 508 addend); 509 510 ARC_DEBUG ("arc_info: TLS_DYNRELOC: type = %d, \ 511GOT_OFFSET = %#lx, GOT_VMA = %#lx, INDEX = %ld, ADDEND = %#lx\n", 512 list->type, 513 (long) got_offset, 514 (long) (htab->sgot->output_section->vma 515 + htab->sgot->output_offset + got_offset), 516 (long) dynindx, (long) addend); 517 } 518 list->created_dyn_relocation = TRUE; 519 } 520} 521 522static void 523create_got_dynrelocs_for_got_info (struct got_entry **list_p, 524 bfd *output_bfd, 525 struct bfd_link_info * info, 526 struct elf_link_hash_entry *h) 527{ 528 if (list_p == NULL) 529 return; 530 531 struct got_entry *list = *list_p; 532 /* Traverse the list of got entries for this symbol. */ 533 while (list) 534 { 535 create_got_dynrelocs_for_single_entry (list, output_bfd, info, h); 536 list = list->next; 537 } 538} 539 540#undef ADD_SYMBOL_REF_SEC_AND_RELOC 541 542#endif /* ARC_GOT_H */ 543