Rev 5197 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 5197 | Rev 6324 | ||
---|---|---|---|
Line 1... | Line 1... | ||
1 | /* ELF STT_GNU_IFUNC support. |
1 | /* ELF STT_GNU_IFUNC support. |
2 | Copyright 2009-2013 |
- | |
3 | Free Software Foundation, Inc. |
2 | Copyright (C) 2009-2015 Free Software Foundation, Inc. |
Line 4... | Line 3... | ||
4 | 3 | ||
Line 5... | Line 4... | ||
5 | This file is part of BFD, the Binary File Descriptor library. |
4 | This file is part of BFD, the Binary File Descriptor library. |
6 | 5 | ||
Line 52... | Line 51... | ||
52 | else |
51 | else |
53 | pltflags |= SEC_ALLOC | SEC_CODE | SEC_LOAD; |
52 | pltflags |= SEC_ALLOC | SEC_CODE | SEC_LOAD; |
54 | if (bed->plt_readonly) |
53 | if (bed->plt_readonly) |
55 | pltflags |= SEC_READONLY; |
54 | pltflags |= SEC_READONLY; |
Line 56... | Line 55... | ||
56 | 55 | ||
57 | if (info->shared) |
56 | if (bfd_link_pic (info)) |
58 | { |
57 | { |
59 | /* We need to create .rel[a].ifunc for shared objects. */ |
58 | /* We need to create .rel[a].ifunc for shared objects. */ |
60 | const char *rel_sec = (bed->rela_plts_and_copies_p |
59 | const char *rel_sec = (bed->rela_plts_and_copies_p |
Line 124... | Line 123... | ||
124 | /* When a shared library references a STT_GNU_IFUNC symbol defined |
123 | /* When a shared library references a STT_GNU_IFUNC symbol defined |
125 | in executable, the address of the resolved function may be used. |
124 | in executable, the address of the resolved function may be used. |
126 | But in non-shared executable, the address of its .plt slot may |
125 | But in non-shared executable, the address of its .plt slot may |
127 | be used. Pointer equality may not work correctly. PIE should |
126 | be used. Pointer equality may not work correctly. PIE should |
128 | be used if pointer equality is required here. */ |
127 | be used if pointer equality is required here. */ |
129 | if (!info->shared |
128 | if (!bfd_link_pic (info) |
130 | && (h->dynindx != -1 |
129 | && (h->dynindx != -1 |
131 | || info->export_dynamic) |
130 | || info->export_dynamic) |
132 | && h->pointer_equality_needed) |
131 | && h->pointer_equality_needed) |
133 | { |
132 | { |
134 | info->callbacks->einfo |
133 | info->callbacks->einfo |
Line 144... | Line 143... | ||
144 | htab = elf_hash_table (info); |
143 | htab = elf_hash_table (info); |
Line 145... | Line 144... | ||
145 | 144 | ||
146 | /* When building shared library, we need to handle the case where it is |
145 | /* When building shared library, we need to handle the case where it is |
147 | marked with regular reference, but not non-GOT reference since the |
146 | marked with regular reference, but not non-GOT reference since the |
148 | non-GOT reference bit may not be set here. */ |
147 | non-GOT reference bit may not be set here. */ |
149 | if (info->shared && !h->non_got_ref && h->ref_regular) |
148 | if (bfd_link_pic (info) && !h->non_got_ref && h->ref_regular) |
150 | for (p = *head; p != NULL; p = p->next) |
149 | for (p = *head; p != NULL; p = p->next) |
151 | if (p->count) |
150 | if (p->count) |
152 | { |
151 | { |
153 | h->non_got_ref = 1; |
152 | h->non_got_ref = 1; |
Line 219... | Line 218... | ||
219 | relplt->size += sizeof_reloc; |
218 | relplt->size += sizeof_reloc; |
220 | relplt->reloc_count++; |
219 | relplt->reloc_count++; |
Line 221... | Line 220... | ||
221 | 220 | ||
222 | /* We need dynamic relocation for STT_GNU_IFUNC symbol only when |
221 | /* We need dynamic relocation for STT_GNU_IFUNC symbol only when |
223 | there is a non-GOT reference in a shared object. */ |
222 | there is a non-GOT reference in a shared object. */ |
224 | if (!info->shared |
223 | if (!bfd_link_pic (info) |
225 | || !h->non_got_ref) |
224 | || !h->non_got_ref) |
Line 226... | Line 225... | ||
226 | *head = NULL; |
225 | *head = NULL; |
227 | 226 | ||
Line 251... | Line 250... | ||
251 | 4. Use .got.plt if .got isn't used. |
250 | 4. Use .got.plt if .got isn't used. |
252 | 5. Otherwise use .got so that it can be shared among different |
251 | 5. Otherwise use .got so that it can be shared among different |
253 | objects at run-time. |
252 | objects at run-time. |
254 | We only need to relocate .got entry in shared object. */ |
253 | We only need to relocate .got entry in shared object. */ |
255 | if (h->got.refcount <= 0 |
254 | if (h->got.refcount <= 0 |
256 | || (info->shared |
255 | || (bfd_link_pic (info) |
257 | && (h->dynindx == -1 |
256 | && (h->dynindx == -1 |
258 | || h->forced_local)) |
257 | || h->forced_local)) |
259 | || (!info->shared |
258 | || (!bfd_link_pic (info) |
260 | && !h->pointer_equality_needed) |
259 | && !h->pointer_equality_needed) |
261 | || (info->executable && info->shared) |
260 | || bfd_link_pie (info) |
262 | || htab->sgot == NULL) |
261 | || htab->sgot == NULL) |
263 | { |
262 | { |
264 | /* Use .got.plt. */ |
263 | /* Use .got.plt. */ |
265 | h->got.offset = (bfd_vma) -1; |
264 | h->got.offset = (bfd_vma) -1; |
266 | } |
265 | } |
267 | else |
266 | else |
268 | { |
267 | { |
269 | h->got.offset = htab->sgot->size; |
268 | h->got.offset = htab->sgot->size; |
270 | htab->sgot->size += got_entry_size; |
269 | htab->sgot->size += got_entry_size; |
271 | if (info->shared) |
270 | if (bfd_link_pic (info)) |
272 | htab->srelgot->size += sizeof_reloc; |
271 | htab->srelgot->size += sizeof_reloc; |
273 | } |
272 | } |
Line 274... | Line 273... | ||
274 | 273 | ||
275 | return TRUE; |
274 | return TRUE; |
- | 275 | } |
|
- | 276 | ||
- | 277 | /* Similar to _bfd_elf_get_synthetic_symtab, optimized for unsorted PLT |
|
- | 278 | entries. PLT is the PLT section. PLT_SYM_VAL is a function pointer |
|
- | 279 | which returns an array of PLT entry symbol values. */ |
|
- | 280 | ||
- | 281 | long |
|
- | 282 | _bfd_elf_ifunc_get_synthetic_symtab |
|
- | 283 | (bfd *abfd, long symcount ATTRIBUTE_UNUSED, |
|
- | 284 | asymbol **syms ATTRIBUTE_UNUSED, long dynsymcount, asymbol **dynsyms, |
|
- | 285 | asymbol **ret, asection *plt, |
|
- | 286 | bfd_vma *(*get_plt_sym_val) (bfd *, asymbol **, asection *, asection *)) |
|
- | 287 | { |
|
- | 288 | const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
|
- | 289 | asection *relplt; |
|
- | 290 | asymbol *s; |
|
- | 291 | const char *relplt_name; |
|
- | 292 | bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean); |
|
- | 293 | arelent *p; |
|
- | 294 | long count, i, n; |
|
- | 295 | size_t size; |
|
- | 296 | Elf_Internal_Shdr *hdr; |
|
- | 297 | char *names; |
|
- | 298 | bfd_vma *plt_sym_val; |
|
- | 299 | ||
- | 300 | *ret = NULL; |
|
- | 301 | ||
- | 302 | if (plt == NULL) |
|
- | 303 | return 0; |
|
- | 304 | ||
- | 305 | if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0) |
|
- | 306 | return 0; |
|
- | 307 | ||
- | 308 | if (dynsymcount <= 0) |
|
- | 309 | return 0; |
|
- | 310 | ||
- | 311 | relplt_name = bed->relplt_name; |
|
- | 312 | if (relplt_name == NULL) |
|
- | 313 | relplt_name = bed->rela_plts_and_copies_p ? ".rela.plt" : ".rel.plt"; |
|
- | 314 | relplt = bfd_get_section_by_name (abfd, relplt_name); |
|
- | 315 | if (relplt == NULL) |
|
- | 316 | return 0; |
|
- | 317 | ||
- | 318 | hdr = &elf_section_data (relplt)->this_hdr; |
|
- | 319 | if (hdr->sh_link != elf_dynsymtab (abfd) |
|
- | 320 | || (hdr->sh_type != SHT_REL && hdr->sh_type != SHT_RELA)) |
|
- | 321 | return 0; |
|
- | 322 | ||
- | 323 | slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table; |
|
- | 324 | if (! (*slurp_relocs) (abfd, relplt, dynsyms, TRUE)) |
|
- | 325 | return -1; |
|
- | 326 | ||
- | 327 | count = relplt->size / hdr->sh_entsize; |
|
- | 328 | size = count * sizeof (asymbol); |
|
- | 329 | p = relplt->relocation; |
|
- | 330 | for (i = 0; i < count; i++, p += bed->s->int_rels_per_ext_rel) |
|
- | 331 | { |
|
- | 332 | size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt"); |
|
- | 333 | if (p->addend != 0) |
|
- | 334 | { |
|
- | 335 | #ifdef BFD64 |
|
- | 336 | size += sizeof ("+0x") - 1 + 8 + 8 * (bed->s->elfclass == ELFCLASS64); |
|
- | 337 | #else |
|
- | 338 | size += sizeof ("+0x") - 1 + 8; |
|
- | 339 | #endif |
|
- | 340 | } |
|
- | 341 | } |
|
- | 342 | ||
- | 343 | plt_sym_val = get_plt_sym_val (abfd, dynsyms, plt, relplt); |
|
- | 344 | if (plt_sym_val == NULL) |
|
- | 345 | return -1; |
|
- | 346 | ||
- | 347 | s = *ret = (asymbol *) bfd_malloc (size); |
|
- | 348 | if (s == NULL) |
|
- | 349 | { |
|
- | 350 | free (plt_sym_val); |
|
- | 351 | return -1; |
|
- | 352 | } |
|
- | 353 | ||
- | 354 | names = (char *) (s + count); |
|
- | 355 | p = relplt->relocation; |
|
- | 356 | n = 0; |
|
- | 357 | for (i = 0; i < count; i++, p += bed->s->int_rels_per_ext_rel) |
|
- | 358 | { |
|
- | 359 | size_t len; |
|
- | 360 | bfd_vma addr; |
|
- | 361 | ||
- | 362 | addr = plt_sym_val[i]; |
|
- | 363 | if (addr == (bfd_vma) -1) |
|
- | 364 | continue; |
|
- | 365 | ||
- | 366 | *s = **p->sym_ptr_ptr; |
|
- | 367 | /* Undefined syms won't have BSF_LOCAL or BSF_GLOBAL set. Since |
|
- | 368 | we are defining a symbol, ensure one of them is set. */ |
|
- | 369 | if ((s->flags & BSF_LOCAL) == 0) |
|
- | 370 | s->flags |= BSF_GLOBAL; |
|
- | 371 | s->flags |= BSF_SYNTHETIC; |
|
- | 372 | s->section = plt; |
|
- | 373 | s->value = addr - plt->vma; |
|
- | 374 | s->name = names; |
|
- | 375 | s->udata.p = NULL; |
|
- | 376 | len = strlen ((*p->sym_ptr_ptr)->name); |
|
- | 377 | memcpy (names, (*p->sym_ptr_ptr)->name, len); |
|
- | 378 | names += len; |
|
- | 379 | if (p->addend != 0) |
|
- | 380 | { |
|
- | 381 | char buf[30], *a; |
|
- | 382 | ||
- | 383 | memcpy (names, "+0x", sizeof ("+0x") - 1); |
|
- | 384 | names += sizeof ("+0x") - 1; |
|
- | 385 | bfd_sprintf_vma (abfd, buf, p->addend); |
|
- | 386 | for (a = buf; *a == '0'; ++a) |
|
- | 387 | ; |
|
- | 388 | len = strlen (a); |
|
- | 389 | memcpy (names, a, len); |
|
- | 390 | names += len; |
|
- | 391 | } |
|
- | 392 | memcpy (names, "@plt", sizeof ("@plt")); |
|
- | 393 | names += sizeof ("@plt"); |
|
- | 394 | ++s, ++n; |
|
- | 395 | } |
|
- | 396 | ||
- | 397 | free (plt_sym_val); |
|
- | 398 | ||
- | 399 | return n; |