189857Sobrien/* .eh_frame section optimization. 2218822Sdim Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007 3218822Sdim Free Software Foundation, Inc. 489857Sobrien Written by Jakub Jelinek <jakub@redhat.com>. 589857Sobrien 6130561Sobrien This file is part of BFD, the Binary File Descriptor library. 789857Sobrien 8130561Sobrien This program is free software; you can redistribute it and/or modify 9130561Sobrien it under the terms of the GNU General Public License as published by 10130561Sobrien the Free Software Foundation; either version 2 of the License, or 11130561Sobrien (at your option) any later version. 1289857Sobrien 13130561Sobrien This program is distributed in the hope that it will be useful, 14130561Sobrien but WITHOUT ANY WARRANTY; without even the implied warranty of 15130561Sobrien MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16130561Sobrien GNU General Public License for more details. 1789857Sobrien 18130561Sobrien You should have received a copy of the GNU General Public License 19130561Sobrien along with this program; if not, write to the Free Software 20218822Sdim Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 2189857Sobrien 22218822Sdim#include "sysdep.h" 2389857Sobrien#include "bfd.h" 2489857Sobrien#include "libbfd.h" 2589857Sobrien#include "elf-bfd.h" 2689857Sobrien#include "elf/dwarf2.h" 2789857Sobrien 2889857Sobrien#define EH_FRAME_HDR_SIZE 8 2989857Sobrien 30218822Sdimstruct cie 31218822Sdim{ 32218822Sdim unsigned int length; 33218822Sdim unsigned int hash; 34218822Sdim unsigned char version; 35218822Sdim unsigned char local_personality; 36218822Sdim char augmentation[20]; 37218822Sdim bfd_vma code_align; 38218822Sdim bfd_signed_vma data_align; 39218822Sdim bfd_vma ra_column; 40218822Sdim bfd_vma augmentation_size; 41218822Sdim union { 42218822Sdim struct elf_link_hash_entry *h; 43218822Sdim bfd_vma val; 44218822Sdim } personality; 45218822Sdim asection *output_sec; 46218822Sdim struct eh_cie_fde *cie_inf; 47218822Sdim unsigned char per_encoding; 48218822Sdim unsigned char lsda_encoding; 49218822Sdim unsigned char fde_encoding; 50218822Sdim unsigned char initial_insn_length; 51218822Sdim unsigned char make_relative; 52218822Sdim unsigned char make_lsda_relative; 53218822Sdim unsigned char initial_instructions[50]; 54218822Sdim}; 5589857Sobrien 56218822Sdim 57218822Sdim 58218822Sdim/* If *ITER hasn't reached END yet, read the next byte into *RESULT and 59218822Sdim move onto the next byte. Return true on success. */ 60218822Sdim 61218822Sdimstatic inline bfd_boolean 62218822Sdimread_byte (bfd_byte **iter, bfd_byte *end, unsigned char *result) 6389857Sobrien{ 64218822Sdim if (*iter >= end) 65218822Sdim return FALSE; 66218822Sdim *result = *((*iter)++); 67218822Sdim return TRUE; 68218822Sdim} 6989857Sobrien 70218822Sdim/* Move *ITER over LENGTH bytes, or up to END, whichever is closer. 71218822Sdim Return true it was possible to move LENGTH bytes. */ 72218822Sdim 73218822Sdimstatic inline bfd_boolean 74218822Sdimskip_bytes (bfd_byte **iter, bfd_byte *end, bfd_size_type length) 75218822Sdim{ 76218822Sdim if ((bfd_size_type) (end - *iter) < length) 7789857Sobrien { 78218822Sdim *iter = end; 79218822Sdim return FALSE; 8089857Sobrien } 81218822Sdim *iter += length; 82218822Sdim return TRUE; 8389857Sobrien} 8489857Sobrien 85218822Sdim/* Move *ITER over an leb128, stopping at END. Return true if the end 86218822Sdim of the leb128 was found. */ 8789857Sobrien 88218822Sdimstatic bfd_boolean 89218822Sdimskip_leb128 (bfd_byte **iter, bfd_byte *end) 9089857Sobrien{ 9189857Sobrien unsigned char byte; 9289857Sobrien do 93218822Sdim if (!read_byte (iter, end, &byte)) 94218822Sdim return FALSE; 9589857Sobrien while (byte & 0x80); 96218822Sdim return TRUE; 9789857Sobrien} 9889857Sobrien 99218822Sdim/* Like skip_leb128, but treat the leb128 as an unsigned value and 100218822Sdim store it in *VALUE. */ 10189857Sobrien 102218822Sdimstatic bfd_boolean 103218822Sdimread_uleb128 (bfd_byte **iter, bfd_byte *end, bfd_vma *value) 104218822Sdim{ 105218822Sdim bfd_byte *start, *p; 10689857Sobrien 107218822Sdim start = *iter; 108218822Sdim if (!skip_leb128 (iter, end)) 109218822Sdim return FALSE; 110218822Sdim 111218822Sdim p = *iter; 112218822Sdim *value = *--p; 113218822Sdim while (p > start) 114218822Sdim *value = (*value << 7) | (*--p & 0x7f); 115218822Sdim 116218822Sdim return TRUE; 117218822Sdim} 118218822Sdim 119218822Sdim/* Like read_uleb128, but for signed values. */ 120218822Sdim 121218822Sdimstatic bfd_boolean 122218822Sdimread_sleb128 (bfd_byte **iter, bfd_byte *end, bfd_signed_vma *value) 123218822Sdim{ 124218822Sdim bfd_byte *start, *p; 125218822Sdim 126218822Sdim start = *iter; 127218822Sdim if (!skip_leb128 (iter, end)) 128218822Sdim return FALSE; 129218822Sdim 130218822Sdim p = *iter; 131218822Sdim *value = ((*--p & 0x7f) ^ 0x40) - 0x40; 132218822Sdim while (p > start) 133218822Sdim *value = (*value << 7) | (*--p & 0x7f); 134218822Sdim 135218822Sdim return TRUE; 136218822Sdim} 137218822Sdim 13889857Sobrien/* Return 0 if either encoding is variable width, or not yet known to bfd. */ 13989857Sobrien 14089857Sobrienstatic 141130561Sobrienint get_DW_EH_PE_width (int encoding, int ptr_size) 14289857Sobrien{ 14389857Sobrien /* DW_EH_PE_ values of 0x60 and 0x70 weren't defined at the time .eh_frame 14489857Sobrien was added to bfd. */ 14589857Sobrien if ((encoding & 0x60) == 0x60) 14689857Sobrien return 0; 14789857Sobrien 14889857Sobrien switch (encoding & 7) 14989857Sobrien { 15089857Sobrien case DW_EH_PE_udata2: return 2; 15189857Sobrien case DW_EH_PE_udata4: return 4; 15289857Sobrien case DW_EH_PE_udata8: return 8; 15389857Sobrien case DW_EH_PE_absptr: return ptr_size; 15489857Sobrien default: 15589857Sobrien break; 15689857Sobrien } 15789857Sobrien 15889857Sobrien return 0; 15989857Sobrien} 16089857Sobrien 161130561Sobrien#define get_DW_EH_PE_signed(encoding) (((encoding) & DW_EH_PE_signed) != 0) 162130561Sobrien 16389857Sobrien/* Read a width sized value from memory. */ 16489857Sobrien 16589857Sobrienstatic bfd_vma 166130561Sobrienread_value (bfd *abfd, bfd_byte *buf, int width, int is_signed) 16789857Sobrien{ 16889857Sobrien bfd_vma value; 16989857Sobrien 17089857Sobrien switch (width) 17189857Sobrien { 172130561Sobrien case 2: 173130561Sobrien if (is_signed) 174130561Sobrien value = bfd_get_signed_16 (abfd, buf); 175130561Sobrien else 176130561Sobrien value = bfd_get_16 (abfd, buf); 177130561Sobrien break; 178130561Sobrien case 4: 179130561Sobrien if (is_signed) 180130561Sobrien value = bfd_get_signed_32 (abfd, buf); 181130561Sobrien else 182130561Sobrien value = bfd_get_32 (abfd, buf); 183130561Sobrien break; 184130561Sobrien case 8: 185130561Sobrien if (is_signed) 186130561Sobrien value = bfd_get_signed_64 (abfd, buf); 187130561Sobrien else 188130561Sobrien value = bfd_get_64 (abfd, buf); 189130561Sobrien break; 190130561Sobrien default: 191130561Sobrien BFD_FAIL (); 192130561Sobrien return 0; 19389857Sobrien } 19489857Sobrien 19589857Sobrien return value; 19689857Sobrien} 197130561Sobrien 19889857Sobrien/* Store a width sized value to memory. */ 19989857Sobrien 20089857Sobrienstatic void 201130561Sobrienwrite_value (bfd *abfd, bfd_byte *buf, bfd_vma value, int width) 20289857Sobrien{ 20389857Sobrien switch (width) 20489857Sobrien { 20589857Sobrien case 2: bfd_put_16 (abfd, value, buf); break; 20689857Sobrien case 4: bfd_put_32 (abfd, value, buf); break; 20789857Sobrien case 8: bfd_put_64 (abfd, value, buf); break; 20889857Sobrien default: BFD_FAIL (); 20989857Sobrien } 21089857Sobrien} 21189857Sobrien 212218822Sdim/* Return one if C1 and C2 CIEs can be merged. */ 21389857Sobrien 214218822Sdimstatic int 215218822Sdimcie_eq (const void *e1, const void *e2) 21689857Sobrien{ 217218822Sdim const struct cie *c1 = e1; 218218822Sdim const struct cie *c2 = e2; 219218822Sdim 220218822Sdim if (c1->hash == c2->hash 221218822Sdim && c1->length == c2->length 22289857Sobrien && c1->version == c2->version 223218822Sdim && c1->local_personality == c2->local_personality 22489857Sobrien && strcmp (c1->augmentation, c2->augmentation) == 0 22589857Sobrien && strcmp (c1->augmentation, "eh") != 0 22689857Sobrien && c1->code_align == c2->code_align 22789857Sobrien && c1->data_align == c2->data_align 22889857Sobrien && c1->ra_column == c2->ra_column 22989857Sobrien && c1->augmentation_size == c2->augmentation_size 230218822Sdim && memcmp (&c1->personality, &c2->personality, 231218822Sdim sizeof (c1->personality)) == 0 232218822Sdim && c1->output_sec == c2->output_sec 23389857Sobrien && c1->per_encoding == c2->per_encoding 23489857Sobrien && c1->lsda_encoding == c2->lsda_encoding 23589857Sobrien && c1->fde_encoding == c2->fde_encoding 236130561Sobrien && c1->initial_insn_length == c2->initial_insn_length 23789857Sobrien && memcmp (c1->initial_instructions, 23889857Sobrien c2->initial_instructions, 23989857Sobrien c1->initial_insn_length) == 0) 240218822Sdim return 1; 241218822Sdim 242218822Sdim return 0; 243218822Sdim} 244218822Sdim 245218822Sdimstatic hashval_t 246218822Sdimcie_hash (const void *e) 247218822Sdim{ 248218822Sdim const struct cie *c = e; 249218822Sdim return c->hash; 250218822Sdim} 251218822Sdim 252218822Sdimstatic hashval_t 253218822Sdimcie_compute_hash (struct cie *c) 254218822Sdim{ 255218822Sdim hashval_t h = 0; 256218822Sdim h = iterative_hash_object (c->length, h); 257218822Sdim h = iterative_hash_object (c->version, h); 258218822Sdim h = iterative_hash (c->augmentation, strlen (c->augmentation) + 1, h); 259218822Sdim h = iterative_hash_object (c->code_align, h); 260218822Sdim h = iterative_hash_object (c->data_align, h); 261218822Sdim h = iterative_hash_object (c->ra_column, h); 262218822Sdim h = iterative_hash_object (c->augmentation_size, h); 263218822Sdim h = iterative_hash_object (c->personality, h); 264218822Sdim h = iterative_hash_object (c->output_sec, h); 265218822Sdim h = iterative_hash_object (c->per_encoding, h); 266218822Sdim h = iterative_hash_object (c->lsda_encoding, h); 267218822Sdim h = iterative_hash_object (c->fde_encoding, h); 268218822Sdim h = iterative_hash_object (c->initial_insn_length, h); 269218822Sdim h = iterative_hash (c->initial_instructions, c->initial_insn_length, h); 270218822Sdim c->hash = h; 271218822Sdim return h; 272218822Sdim} 273218822Sdim 274218822Sdim/* Return the number of extra bytes that we'll be inserting into 275218822Sdim ENTRY's augmentation string. */ 276218822Sdim 277218822Sdimstatic INLINE unsigned int 278218822Sdimextra_augmentation_string_bytes (struct eh_cie_fde *entry) 279218822Sdim{ 280218822Sdim unsigned int size = 0; 281218822Sdim if (entry->cie) 282218822Sdim { 283218822Sdim if (entry->add_augmentation_size) 284218822Sdim size++; 285218822Sdim if (entry->add_fde_encoding) 286218822Sdim size++; 287218822Sdim } 288218822Sdim return size; 289218822Sdim} 290218822Sdim 291218822Sdim/* Likewise ENTRY's augmentation data. */ 292218822Sdim 293218822Sdimstatic INLINE unsigned int 294218822Sdimextra_augmentation_data_bytes (struct eh_cie_fde *entry) 295218822Sdim{ 296218822Sdim unsigned int size = 0; 297218822Sdim if (entry->cie) 298218822Sdim { 299218822Sdim if (entry->add_augmentation_size) 300218822Sdim size++; 301218822Sdim if (entry->add_fde_encoding) 302218822Sdim size++; 303218822Sdim } 304218822Sdim else 305218822Sdim { 306218822Sdim if (entry->cie_inf->add_augmentation_size) 307218822Sdim size++; 308218822Sdim } 309218822Sdim return size; 310218822Sdim} 311218822Sdim 312218822Sdim/* Return the size that ENTRY will have in the output. ALIGNMENT is the 313218822Sdim required alignment of ENTRY in bytes. */ 314218822Sdim 315218822Sdimstatic unsigned int 316218822Sdimsize_of_output_cie_fde (struct eh_cie_fde *entry, unsigned int alignment) 317218822Sdim{ 318218822Sdim if (entry->removed) 31989857Sobrien return 0; 320218822Sdim if (entry->size == 4) 321218822Sdim return 4; 322218822Sdim return (entry->size 323218822Sdim + extra_augmentation_string_bytes (entry) 324218822Sdim + extra_augmentation_data_bytes (entry) 325218822Sdim + alignment - 1) & -alignment; 326218822Sdim} 32789857Sobrien 328218822Sdim/* Assume that the bytes between *ITER and END are CFA instructions. 329218822Sdim Try to move *ITER past the first instruction and return true on 330218822Sdim success. ENCODED_PTR_WIDTH gives the width of pointer entries. */ 331218822Sdim 332218822Sdimstatic bfd_boolean 333218822Sdimskip_cfa_op (bfd_byte **iter, bfd_byte *end, unsigned int encoded_ptr_width) 334218822Sdim{ 335218822Sdim bfd_byte op; 336218822Sdim bfd_vma length; 337218822Sdim 338218822Sdim if (!read_byte (iter, end, &op)) 339218822Sdim return FALSE; 340218822Sdim 341218822Sdim switch (op & 0xc0 ? op & 0xc0 : op) 342218822Sdim { 343218822Sdim case DW_CFA_nop: 344218822Sdim case DW_CFA_advance_loc: 345218822Sdim case DW_CFA_restore: 346218822Sdim case DW_CFA_remember_state: 347218822Sdim case DW_CFA_restore_state: 348218822Sdim case DW_CFA_GNU_window_save: 349218822Sdim /* No arguments. */ 350218822Sdim return TRUE; 351218822Sdim 352218822Sdim case DW_CFA_offset: 353218822Sdim case DW_CFA_restore_extended: 354218822Sdim case DW_CFA_undefined: 355218822Sdim case DW_CFA_same_value: 356218822Sdim case DW_CFA_def_cfa_register: 357218822Sdim case DW_CFA_def_cfa_offset: 358218822Sdim case DW_CFA_def_cfa_offset_sf: 359218822Sdim case DW_CFA_GNU_args_size: 360218822Sdim /* One leb128 argument. */ 361218822Sdim return skip_leb128 (iter, end); 362218822Sdim 363218822Sdim case DW_CFA_val_offset: 364218822Sdim case DW_CFA_val_offset_sf: 365218822Sdim case DW_CFA_offset_extended: 366218822Sdim case DW_CFA_register: 367218822Sdim case DW_CFA_def_cfa: 368218822Sdim case DW_CFA_offset_extended_sf: 369218822Sdim case DW_CFA_GNU_negative_offset_extended: 370218822Sdim case DW_CFA_def_cfa_sf: 371218822Sdim /* Two leb128 arguments. */ 372218822Sdim return (skip_leb128 (iter, end) 373218822Sdim && skip_leb128 (iter, end)); 374218822Sdim 375218822Sdim case DW_CFA_def_cfa_expression: 376218822Sdim /* A variable-length argument. */ 377218822Sdim return (read_uleb128 (iter, end, &length) 378218822Sdim && skip_bytes (iter, end, length)); 379218822Sdim 380218822Sdim case DW_CFA_expression: 381218822Sdim case DW_CFA_val_expression: 382218822Sdim /* A leb128 followed by a variable-length argument. */ 383218822Sdim return (skip_leb128 (iter, end) 384218822Sdim && read_uleb128 (iter, end, &length) 385218822Sdim && skip_bytes (iter, end, length)); 386218822Sdim 387218822Sdim case DW_CFA_set_loc: 388218822Sdim return skip_bytes (iter, end, encoded_ptr_width); 389218822Sdim 390218822Sdim case DW_CFA_advance_loc1: 391218822Sdim return skip_bytes (iter, end, 1); 392218822Sdim 393218822Sdim case DW_CFA_advance_loc2: 394218822Sdim return skip_bytes (iter, end, 2); 395218822Sdim 396218822Sdim case DW_CFA_advance_loc4: 397218822Sdim return skip_bytes (iter, end, 4); 398218822Sdim 399218822Sdim case DW_CFA_MIPS_advance_loc8: 400218822Sdim return skip_bytes (iter, end, 8); 401218822Sdim 402218822Sdim default: 403218822Sdim return FALSE; 404218822Sdim } 40589857Sobrien} 40689857Sobrien 407218822Sdim/* Try to interpret the bytes between BUF and END as CFA instructions. 408218822Sdim If every byte makes sense, return a pointer to the first DW_CFA_nop 409218822Sdim padding byte, or END if there is no padding. Return null otherwise. 410218822Sdim ENCODED_PTR_WIDTH is as for skip_cfa_op. */ 411218822Sdim 412218822Sdimstatic bfd_byte * 413218822Sdimskip_non_nops (bfd_byte *buf, bfd_byte *end, unsigned int encoded_ptr_width, 414218822Sdim unsigned int *set_loc_count) 415218822Sdim{ 416218822Sdim bfd_byte *last; 417218822Sdim 418218822Sdim last = buf; 419218822Sdim while (buf < end) 420218822Sdim if (*buf == DW_CFA_nop) 421218822Sdim buf++; 422218822Sdim else 423218822Sdim { 424218822Sdim if (*buf == DW_CFA_set_loc) 425218822Sdim ++*set_loc_count; 426218822Sdim if (!skip_cfa_op (&buf, end, encoded_ptr_width)) 427218822Sdim return 0; 428218822Sdim last = buf; 429218822Sdim } 430218822Sdim return last; 431218822Sdim} 432218822Sdim 43389857Sobrien/* This function is called for each input file before the .eh_frame 43489857Sobrien section is relocated. It discards duplicate CIEs and FDEs for discarded 435130561Sobrien functions. The function returns TRUE iff any entries have been 43689857Sobrien deleted. */ 43789857Sobrien 438130561Sobrienbfd_boolean 439130561Sobrien_bfd_elf_discard_section_eh_frame 440130561Sobrien (bfd *abfd, struct bfd_link_info *info, asection *sec, 441130561Sobrien bfd_boolean (*reloc_symbol_deleted_p) (bfd_vma, void *), 442130561Sobrien struct elf_reloc_cookie *cookie) 44389857Sobrien{ 444218822Sdim#define REQUIRE(COND) \ 445218822Sdim do \ 446218822Sdim if (!(COND)) \ 447218822Sdim goto free_no_table; \ 448218822Sdim while (0) 449218822Sdim 45089857Sobrien bfd_byte *ehbuf = NULL, *buf; 451218822Sdim bfd_byte *last_fde; 452218822Sdim struct eh_cie_fde *ent, *this_inf; 453218822Sdim unsigned int hdr_length, hdr_id; 454218822Sdim struct extended_cie 455218822Sdim { 456218822Sdim struct cie cie; 457218822Sdim unsigned int offset; 458218822Sdim unsigned int usage_count; 459218822Sdim unsigned int entry; 460218822Sdim } *ecies = NULL, *ecie; 461218822Sdim unsigned int ecie_count = 0, ecie_alloced = 0; 462218822Sdim struct cie *cie; 463130561Sobrien struct elf_link_hash_table *htab; 46489857Sobrien struct eh_frame_hdr_info *hdr_info; 46589857Sobrien struct eh_frame_sec_info *sec_info = NULL; 466218822Sdim unsigned int offset; 46789857Sobrien unsigned int ptr_size; 468218822Sdim unsigned int entry_alloced; 46989857Sobrien 470218822Sdim if (sec->size == 0) 47189857Sobrien { 47289857Sobrien /* This file does not contain .eh_frame information. */ 473130561Sobrien return FALSE; 47489857Sobrien } 47589857Sobrien 476218822Sdim if (bfd_is_abs_section (sec->output_section)) 47789857Sobrien { 47889857Sobrien /* At least one of the sections is being discarded from the 479218822Sdim link, so we should just ignore them. */ 480130561Sobrien return FALSE; 48189857Sobrien } 48289857Sobrien 483130561Sobrien htab = elf_hash_table (info); 484130561Sobrien hdr_info = &htab->eh_info; 48589857Sobrien 486218822Sdim if (hdr_info->cies == NULL && !info->relocatable) 487218822Sdim hdr_info->cies = htab_try_create (1, cie_hash, cie_eq, free); 488218822Sdim 48989857Sobrien /* Read the frame unwind information from abfd. */ 49089857Sobrien 491218822Sdim REQUIRE (bfd_malloc_and_get_section (abfd, sec, &ehbuf)); 49289857Sobrien 493218822Sdim if (sec->size >= 4 49489857Sobrien && bfd_get_32 (abfd, ehbuf) == 0 49589857Sobrien && cookie->rel == cookie->relend) 49689857Sobrien { 49789857Sobrien /* Empty .eh_frame section. */ 49889857Sobrien free (ehbuf); 499130561Sobrien return FALSE; 50089857Sobrien } 50189857Sobrien 50289857Sobrien /* If .eh_frame section size doesn't fit into int, we cannot handle 50389857Sobrien it (it would need to use 64-bit .eh_frame format anyway). */ 504218822Sdim REQUIRE (sec->size == (unsigned int) sec->size); 50589857Sobrien 506218822Sdim ptr_size = (get_elf_backend_data (abfd) 507218822Sdim ->elf_backend_eh_frame_address_size (abfd, sec)); 508218822Sdim REQUIRE (ptr_size != 0); 509218822Sdim 51089857Sobrien buf = ehbuf; 51189857Sobrien sec_info = bfd_zmalloc (sizeof (struct eh_frame_sec_info) 51289857Sobrien + 99 * sizeof (struct eh_cie_fde)); 513218822Sdim REQUIRE (sec_info); 51489857Sobrien 515218822Sdim entry_alloced = 100; 516218822Sdim 51789857Sobrien#define ENSURE_NO_RELOCS(buf) \ 518218822Sdim REQUIRE (!(cookie->rel < cookie->relend \ 519218822Sdim && (cookie->rel->r_offset \ 520218822Sdim < (bfd_size_type) ((buf) - ehbuf)) \ 521218822Sdim && cookie->rel->r_info != 0)) 52289857Sobrien 52389857Sobrien#define SKIP_RELOCS(buf) \ 52489857Sobrien while (cookie->rel < cookie->relend \ 525218822Sdim && (cookie->rel->r_offset \ 52689857Sobrien < (bfd_size_type) ((buf) - ehbuf))) \ 52789857Sobrien cookie->rel++ 52889857Sobrien 52989857Sobrien#define GET_RELOC(buf) \ 53089857Sobrien ((cookie->rel < cookie->relend \ 53189857Sobrien && (cookie->rel->r_offset \ 532218822Sdim == (bfd_size_type) ((buf) - ehbuf))) \ 53389857Sobrien ? cookie->rel : NULL) 53489857Sobrien 53589857Sobrien for (;;) 53689857Sobrien { 537218822Sdim char *aug; 538218822Sdim bfd_byte *start, *end, *insns, *insns_end; 539218822Sdim bfd_size_type length; 540218822Sdim unsigned int set_loc_count; 54189857Sobrien 542218822Sdim if (sec_info->count == entry_alloced) 54389857Sobrien { 54489857Sobrien sec_info = bfd_realloc (sec_info, 54589857Sobrien sizeof (struct eh_frame_sec_info) 546218822Sdim + ((entry_alloced + 99) 547218822Sdim * sizeof (struct eh_cie_fde))); 548218822Sdim REQUIRE (sec_info); 54989857Sobrien 550218822Sdim memset (&sec_info->entry[entry_alloced], 0, 55189857Sobrien 100 * sizeof (struct eh_cie_fde)); 552218822Sdim entry_alloced += 100; 55389857Sobrien } 55489857Sobrien 555218822Sdim this_inf = sec_info->entry + sec_info->count; 55689857Sobrien last_fde = buf; 55789857Sobrien 558218822Sdim if ((bfd_size_type) (buf - ehbuf) == sec->size) 559218822Sdim break; 56089857Sobrien 561218822Sdim /* Read the length of the entry. */ 562218822Sdim REQUIRE (skip_bytes (&buf, ehbuf + sec->size, 4)); 563218822Sdim hdr_length = bfd_get_32 (abfd, buf - 4); 56489857Sobrien 565218822Sdim /* 64-bit .eh_frame is not supported. */ 566218822Sdim REQUIRE (hdr_length != 0xffffffff); 567218822Sdim 568218822Sdim /* The CIE/FDE must be fully contained in this input section. */ 569218822Sdim REQUIRE ((bfd_size_type) (buf - ehbuf) + hdr_length <= sec->size); 570218822Sdim end = buf + hdr_length; 571218822Sdim 572218822Sdim this_inf->offset = last_fde - ehbuf; 573218822Sdim this_inf->size = 4 + hdr_length; 574218822Sdim 575218822Sdim if (hdr_length == 0) 576218822Sdim { 577218822Sdim /* A zero-length CIE should only be found at the end of 578218822Sdim the section. */ 579218822Sdim REQUIRE ((bfd_size_type) (buf - ehbuf) == sec->size); 580218822Sdim ENSURE_NO_RELOCS (buf); 581218822Sdim sec_info->count++; 582218822Sdim break; 58389857Sobrien } 58489857Sobrien 585218822Sdim REQUIRE (skip_bytes (&buf, end, 4)); 586218822Sdim hdr_id = bfd_get_32 (abfd, buf - 4); 587218822Sdim 588218822Sdim if (hdr_id == 0) 58989857Sobrien { 59089857Sobrien unsigned int initial_insn_length; 59189857Sobrien 59289857Sobrien /* CIE */ 593218822Sdim this_inf->cie = 1; 594218822Sdim 595218822Sdim if (ecie_count == ecie_alloced) 59689857Sobrien { 597218822Sdim ecies = bfd_realloc (ecies, 598218822Sdim (ecie_alloced + 20) * sizeof (*ecies)); 599218822Sdim REQUIRE (ecies); 600218822Sdim memset (&ecies[ecie_alloced], 0, 20 * sizeof (*ecies)); 601218822Sdim ecie_alloced += 20; 60289857Sobrien } 60389857Sobrien 604218822Sdim cie = &ecies[ecie_count].cie; 605218822Sdim ecies[ecie_count].offset = this_inf->offset; 606218822Sdim ecies[ecie_count++].entry = sec_info->count; 607218822Sdim cie->length = hdr_length; 608218822Sdim start = buf; 609218822Sdim REQUIRE (read_byte (&buf, end, &cie->version)); 61089857Sobrien 61189857Sobrien /* Cannot handle unknown versions. */ 612218822Sdim REQUIRE (cie->version == 1 || cie->version == 3); 613218822Sdim REQUIRE (strlen ((char *) buf) < sizeof (cie->augmentation)); 61489857Sobrien 615218822Sdim strcpy (cie->augmentation, (char *) buf); 616218822Sdim buf = (bfd_byte *) strchr ((char *) buf, '\0') + 1; 61789857Sobrien ENSURE_NO_RELOCS (buf); 61889857Sobrien if (buf[0] == 'e' && buf[1] == 'h') 61989857Sobrien { 62089857Sobrien /* GCC < 3.0 .eh_frame CIE */ 62189857Sobrien /* We cannot merge "eh" CIEs because __EXCEPTION_TABLE__ 62289857Sobrien is private to each CIE, so we don't need it for anything. 62389857Sobrien Just skip it. */ 624218822Sdim REQUIRE (skip_bytes (&buf, end, ptr_size)); 62589857Sobrien SKIP_RELOCS (buf); 62689857Sobrien } 627218822Sdim REQUIRE (read_uleb128 (&buf, end, &cie->code_align)); 628218822Sdim REQUIRE (read_sleb128 (&buf, end, &cie->data_align)); 629218822Sdim if (cie->version == 1) 630218822Sdim { 631218822Sdim REQUIRE (buf < end); 632218822Sdim cie->ra_column = *buf++; 633218822Sdim } 634218822Sdim else 635218822Sdim REQUIRE (read_uleb128 (&buf, end, &cie->ra_column)); 63689857Sobrien ENSURE_NO_RELOCS (buf); 637218822Sdim cie->lsda_encoding = DW_EH_PE_omit; 638218822Sdim cie->fde_encoding = DW_EH_PE_omit; 639218822Sdim cie->per_encoding = DW_EH_PE_omit; 640218822Sdim aug = cie->augmentation; 64189857Sobrien if (aug[0] != 'e' || aug[1] != 'h') 64289857Sobrien { 64389857Sobrien if (*aug == 'z') 64489857Sobrien { 64589857Sobrien aug++; 646218822Sdim REQUIRE (read_uleb128 (&buf, end, &cie->augmentation_size)); 64789857Sobrien ENSURE_NO_RELOCS (buf); 64889857Sobrien } 64989857Sobrien 65089857Sobrien while (*aug != '\0') 65189857Sobrien switch (*aug++) 65289857Sobrien { 65389857Sobrien case 'L': 654218822Sdim REQUIRE (read_byte (&buf, end, &cie->lsda_encoding)); 65589857Sobrien ENSURE_NO_RELOCS (buf); 656218822Sdim REQUIRE (get_DW_EH_PE_width (cie->lsda_encoding, ptr_size)); 65789857Sobrien break; 65889857Sobrien case 'R': 659218822Sdim REQUIRE (read_byte (&buf, end, &cie->fde_encoding)); 66089857Sobrien ENSURE_NO_RELOCS (buf); 661218822Sdim REQUIRE (get_DW_EH_PE_width (cie->fde_encoding, ptr_size)); 66289857Sobrien break; 663218822Sdim case 'S': 664218822Sdim break; 66589857Sobrien case 'P': 66689857Sobrien { 66789857Sobrien int per_width; 66889857Sobrien 669218822Sdim REQUIRE (read_byte (&buf, end, &cie->per_encoding)); 670218822Sdim per_width = get_DW_EH_PE_width (cie->per_encoding, 67189857Sobrien ptr_size); 672218822Sdim REQUIRE (per_width); 673218822Sdim if ((cie->per_encoding & 0xf0) == DW_EH_PE_aligned) 674218822Sdim { 675218822Sdim length = -(buf - ehbuf) & (per_width - 1); 676218822Sdim REQUIRE (skip_bytes (&buf, end, length)); 677218822Sdim } 67889857Sobrien ENSURE_NO_RELOCS (buf); 679218822Sdim /* Ensure we have a reloc here. */ 680130561Sobrien if (GET_RELOC (buf) != NULL) 68189857Sobrien { 68289857Sobrien unsigned long r_symndx; 68389857Sobrien 68489857Sobrien#ifdef BFD64 68589857Sobrien if (ptr_size == 8) 68689857Sobrien r_symndx = ELF64_R_SYM (cookie->rel->r_info); 68789857Sobrien else 68889857Sobrien#endif 68989857Sobrien r_symndx = ELF32_R_SYM (cookie->rel->r_info); 690218822Sdim if (r_symndx >= cookie->locsymcount 691218822Sdim || ELF_ST_BIND (cookie->locsyms[r_symndx] 692218822Sdim .st_info) != STB_LOCAL) 69389857Sobrien { 69489857Sobrien struct elf_link_hash_entry *h; 69589857Sobrien 69689857Sobrien r_symndx -= cookie->extsymoff; 69789857Sobrien h = cookie->sym_hashes[r_symndx]; 69889857Sobrien 69989857Sobrien while (h->root.type == bfd_link_hash_indirect 70089857Sobrien || h->root.type == bfd_link_hash_warning) 70189857Sobrien h = (struct elf_link_hash_entry *) 70289857Sobrien h->root.u.i.link; 70389857Sobrien 704218822Sdim cie->personality.h = h; 70589857Sobrien } 706218822Sdim else 707218822Sdim { 708218822Sdim Elf_Internal_Sym *sym; 709218822Sdim asection *sym_sec; 710218822Sdim bfd_vma val; 711218822Sdim 712218822Sdim sym = &cookie->locsyms[r_symndx]; 713218822Sdim sym_sec = (bfd_section_from_elf_index 714218822Sdim (abfd, sym->st_shndx)); 715218822Sdim if (sym_sec != NULL) 716218822Sdim { 717218822Sdim if (sym_sec->kept_section != NULL) 718218822Sdim sym_sec = sym_sec->kept_section; 719218822Sdim if (sym_sec->output_section != NULL) 720218822Sdim { 721218822Sdim val = (sym->st_value 722218822Sdim + sym_sec->output_offset 723218822Sdim + sym_sec->output_section->vma); 724218822Sdim cie->personality.val = val; 725218822Sdim cie->local_personality = 1; 726218822Sdim } 727218822Sdim } 728218822Sdim } 729218822Sdim 730218822Sdim /* Cope with MIPS-style composite relocations. */ 731218822Sdim do 732218822Sdim cookie->rel++; 733218822Sdim while (GET_RELOC (buf) != NULL); 73489857Sobrien } 735218822Sdim REQUIRE (skip_bytes (&buf, end, per_width)); 736218822Sdim REQUIRE (cie->local_personality || cie->personality.h); 73789857Sobrien } 73889857Sobrien break; 73989857Sobrien default: 74089857Sobrien /* Unrecognized augmentation. Better bail out. */ 74189857Sobrien goto free_no_table; 74289857Sobrien } 74389857Sobrien } 74489857Sobrien 74589857Sobrien /* For shared libraries, try to get rid of as many RELATIVE relocs 74691041Sobrien as possible. */ 747218822Sdim if (info->shared 748130561Sobrien && (get_elf_backend_data (abfd) 749130561Sobrien ->elf_backend_can_make_relative_eh_frame 750218822Sdim (abfd, info, sec))) 751218822Sdim { 752218822Sdim if ((cie->fde_encoding & 0xf0) == DW_EH_PE_absptr) 753218822Sdim cie->make_relative = 1; 754218822Sdim /* If the CIE doesn't already have an 'R' entry, it's fairly 755218822Sdim easy to add one, provided that there's no aligned data 756218822Sdim after the augmentation string. */ 757218822Sdim else if (cie->fde_encoding == DW_EH_PE_omit 758218822Sdim && (cie->per_encoding & 0xf0) != DW_EH_PE_aligned) 759218822Sdim { 760218822Sdim if (*cie->augmentation == 0) 761218822Sdim this_inf->add_augmentation_size = 1; 762218822Sdim this_inf->add_fde_encoding = 1; 763218822Sdim cie->make_relative = 1; 764218822Sdim } 765218822Sdim } 76689857Sobrien 76791041Sobrien if (info->shared 768130561Sobrien && (get_elf_backend_data (abfd) 769130561Sobrien ->elf_backend_can_make_lsda_relative_eh_frame 770130561Sobrien (abfd, info, sec)) 771218822Sdim && (cie->lsda_encoding & 0xf0) == DW_EH_PE_absptr) 772218822Sdim cie->make_lsda_relative = 1; 77389857Sobrien 77489857Sobrien /* If FDE encoding was not specified, it defaults to 77589857Sobrien DW_EH_absptr. */ 776218822Sdim if (cie->fde_encoding == DW_EH_PE_omit) 777218822Sdim cie->fde_encoding = DW_EH_PE_absptr; 77889857Sobrien 779218822Sdim initial_insn_length = end - buf; 780218822Sdim if (initial_insn_length <= sizeof (cie->initial_instructions)) 78189857Sobrien { 782218822Sdim cie->initial_insn_length = initial_insn_length; 783218822Sdim memcpy (cie->initial_instructions, buf, initial_insn_length); 78489857Sobrien } 785218822Sdim insns = buf; 78689857Sobrien buf += initial_insn_length; 78789857Sobrien ENSURE_NO_RELOCS (buf); 78889857Sobrien } 78989857Sobrien else 79089857Sobrien { 791218822Sdim /* Find the corresponding CIE. */ 792218822Sdim unsigned int cie_offset = this_inf->offset + 4 - hdr_id; 793218822Sdim for (ecie = ecies; ecie < ecies + ecie_count; ++ecie) 794218822Sdim if (cie_offset == ecie->offset) 795218822Sdim break; 79689857Sobrien 797218822Sdim /* Ensure this FDE references one of the CIEs in this input 798218822Sdim section. */ 799218822Sdim REQUIRE (ecie != ecies + ecie_count); 800218822Sdim cie = &ecie->cie; 801218822Sdim 80289857Sobrien ENSURE_NO_RELOCS (buf); 803218822Sdim REQUIRE (GET_RELOC (buf)); 804218822Sdim 80589857Sobrien if ((*reloc_symbol_deleted_p) (buf - ehbuf, cookie)) 806218822Sdim /* This is a FDE against a discarded section. It should 807218822Sdim be deleted. */ 808218822Sdim this_inf->removed = 1; 80989857Sobrien else 81089857Sobrien { 81191041Sobrien if (info->shared 812218822Sdim && (((cie->fde_encoding & 0xf0) == DW_EH_PE_absptr 813218822Sdim && cie->make_relative == 0) 814218822Sdim || (cie->fde_encoding & 0xf0) == DW_EH_PE_aligned)) 81591041Sobrien { 816130561Sobrien /* If a shared library uses absolute pointers 81791041Sobrien which we cannot turn into PC relative, 81891041Sobrien don't create the binary search table, 81991041Sobrien since it is affected by runtime relocations. */ 820130561Sobrien hdr_info->table = FALSE; 821218822Sdim (*info->callbacks->einfo) 822218822Sdim (_("%P: fde encoding in %B(%A) prevents .eh_frame_hdr" 823218822Sdim " table being created.\n"), abfd, sec); 82491041Sobrien } 825218822Sdim ecie->usage_count++; 82689857Sobrien hdr_info->fde_count++; 827218822Sdim this_inf->cie_inf = (void *) (ecie - ecies); 82889857Sobrien } 829218822Sdim 830218822Sdim /* Skip the initial location and address range. */ 831218822Sdim start = buf; 832218822Sdim length = get_DW_EH_PE_width (cie->fde_encoding, ptr_size); 833218822Sdim REQUIRE (skip_bytes (&buf, end, 2 * length)); 834218822Sdim 835218822Sdim /* Skip the augmentation size, if present. */ 836218822Sdim if (cie->augmentation[0] == 'z') 837218822Sdim REQUIRE (read_uleb128 (&buf, end, &length)); 838218822Sdim else 839218822Sdim length = 0; 840218822Sdim 841218822Sdim /* Of the supported augmentation characters above, only 'L' 842218822Sdim adds augmentation data to the FDE. This code would need to 843218822Sdim be adjusted if any future augmentations do the same thing. */ 844218822Sdim if (cie->lsda_encoding != DW_EH_PE_omit) 84589857Sobrien { 846218822Sdim this_inf->lsda_offset = buf - start; 847218822Sdim /* If there's no 'z' augmentation, we don't know where the 848218822Sdim CFA insns begin. Assume no padding. */ 849218822Sdim if (cie->augmentation[0] != 'z') 850218822Sdim length = end - buf; 851218822Sdim } 85289857Sobrien 853218822Sdim /* Skip over the augmentation data. */ 854218822Sdim REQUIRE (skip_bytes (&buf, end, length)); 855218822Sdim insns = buf; 856218822Sdim 857218822Sdim buf = last_fde + 4 + hdr_length; 85889857Sobrien SKIP_RELOCS (buf); 85989857Sobrien } 86089857Sobrien 861218822Sdim /* Try to interpret the CFA instructions and find the first 862218822Sdim padding nop. Shrink this_inf's size so that it doesn't 863218822Sdim include the padding. */ 864218822Sdim length = get_DW_EH_PE_width (cie->fde_encoding, ptr_size); 865218822Sdim set_loc_count = 0; 866218822Sdim insns_end = skip_non_nops (insns, end, length, &set_loc_count); 867218822Sdim /* If we don't understand the CFA instructions, we can't know 868218822Sdim what needs to be adjusted there. */ 869218822Sdim if (insns_end == NULL 870218822Sdim /* For the time being we don't support DW_CFA_set_loc in 871218822Sdim CIE instructions. */ 872218822Sdim || (set_loc_count && this_inf->cie)) 873218822Sdim goto free_no_table; 874218822Sdim this_inf->size -= end - insns_end; 875218822Sdim if (insns_end != end && this_inf->cie) 876218822Sdim { 877218822Sdim cie->initial_insn_length -= end - insns_end; 878218822Sdim cie->length -= end - insns_end; 879218822Sdim } 880218822Sdim if (set_loc_count 881218822Sdim && ((cie->fde_encoding & 0xf0) == DW_EH_PE_pcrel 882218822Sdim || cie->make_relative)) 883218822Sdim { 884218822Sdim unsigned int cnt; 885218822Sdim bfd_byte *p; 886218822Sdim 887218822Sdim this_inf->set_loc = bfd_malloc ((set_loc_count + 1) 888218822Sdim * sizeof (unsigned int)); 889218822Sdim REQUIRE (this_inf->set_loc); 890218822Sdim this_inf->set_loc[0] = set_loc_count; 891218822Sdim p = insns; 892218822Sdim cnt = 0; 893218822Sdim while (p < end) 894218822Sdim { 895218822Sdim if (*p == DW_CFA_set_loc) 896218822Sdim this_inf->set_loc[++cnt] = p + 1 - start; 897218822Sdim REQUIRE (skip_cfa_op (&p, end, length)); 898218822Sdim } 899218822Sdim } 900218822Sdim 901218822Sdim this_inf->fde_encoding = cie->fde_encoding; 902218822Sdim this_inf->lsda_encoding = cie->lsda_encoding; 90389857Sobrien sec_info->count++; 90489857Sobrien } 90589857Sobrien 90689857Sobrien elf_section_data (sec)->sec_info = sec_info; 907130561Sobrien sec->sec_info_type = ELF_INFO_TYPE_EH_FRAME; 90889857Sobrien 909218822Sdim /* Look at all CIEs in this section and determine which can be 910218822Sdim removed as unused, which can be merged with previous duplicate 911218822Sdim CIEs and which need to be kept. */ 912218822Sdim for (ecie = ecies; ecie < ecies + ecie_count; ++ecie) 91389857Sobrien { 914218822Sdim if (ecie->usage_count == 0) 91589857Sobrien { 916218822Sdim sec_info->entry[ecie->entry].removed = 1; 917218822Sdim continue; 918218822Sdim } 919218822Sdim ecie->cie.output_sec = sec->output_section; 920218822Sdim ecie->cie.cie_inf = sec_info->entry + ecie->entry; 921218822Sdim cie_compute_hash (&ecie->cie); 922218822Sdim if (hdr_info->cies != NULL) 923218822Sdim { 924218822Sdim void **loc = htab_find_slot_with_hash (hdr_info->cies, &ecie->cie, 925218822Sdim ecie->cie.hash, INSERT); 926218822Sdim if (loc != NULL) 92789857Sobrien { 928218822Sdim if (*loc != HTAB_EMPTY_ENTRY) 929218822Sdim { 930218822Sdim sec_info->entry[ecie->entry].removed = 1; 931218822Sdim ecie->cie.cie_inf = ((struct cie *) *loc)->cie_inf; 932218822Sdim continue; 933218822Sdim } 934218822Sdim 935218822Sdim *loc = malloc (sizeof (struct cie)); 936218822Sdim if (*loc == NULL) 937218822Sdim *loc = HTAB_DELETED_ENTRY; 938218822Sdim else 939218822Sdim memcpy (*loc, &ecie->cie, sizeof (struct cie)); 94089857Sobrien } 94189857Sobrien } 942218822Sdim ecie->cie.cie_inf->make_relative = ecie->cie.make_relative; 943218822Sdim ecie->cie.cie_inf->make_lsda_relative = ecie->cie.make_lsda_relative; 944218822Sdim ecie->cie.cie_inf->per_encoding_relative 945218822Sdim = (ecie->cie.per_encoding & 0x70) == DW_EH_PE_pcrel; 94689857Sobrien } 94789857Sobrien 948218822Sdim /* Ok, now we can assign new offsets. */ 949218822Sdim offset = 0; 950218822Sdim for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent) 951218822Sdim if (!ent->removed) 952218822Sdim { 953218822Sdim if (!ent->cie) 954218822Sdim { 955218822Sdim ecie = ecies + (unsigned long) ent->cie_inf; 956218822Sdim ent->cie_inf = ecie->cie.cie_inf; 957218822Sdim } 958218822Sdim ent->new_offset = offset; 959218822Sdim offset += size_of_output_cie_fde (ent, ptr_size); 960218822Sdim } 96189857Sobrien 962218822Sdim /* Resize the sec as needed. */ 963218822Sdim sec->rawsize = sec->size; 964218822Sdim sec->size = offset; 96589857Sobrien 96689857Sobrien free (ehbuf); 967218822Sdim if (ecies) 968218822Sdim free (ecies); 969218822Sdim return offset != sec->rawsize; 97089857Sobrien 97189857Sobrienfree_no_table: 972218822Sdim (*info->callbacks->einfo) 973218822Sdim (_("%P: error in %B(%A); no .eh_frame_hdr table will be created.\n"), 974218822Sdim abfd, sec); 97589857Sobrien if (ehbuf) 97689857Sobrien free (ehbuf); 97789857Sobrien if (sec_info) 97889857Sobrien free (sec_info); 979218822Sdim if (ecies) 980218822Sdim free (ecies); 981130561Sobrien hdr_info->table = FALSE; 982130561Sobrien return FALSE; 983218822Sdim 984218822Sdim#undef REQUIRE 98589857Sobrien} 98689857Sobrien 98789857Sobrien/* This function is called for .eh_frame_hdr section after 98889857Sobrien _bfd_elf_discard_section_eh_frame has been called on all .eh_frame 98989857Sobrien input sections. It finalizes the size of .eh_frame_hdr section. */ 99089857Sobrien 991130561Sobrienbfd_boolean 992130561Sobrien_bfd_elf_discard_section_eh_frame_hdr (bfd *abfd, struct bfd_link_info *info) 99389857Sobrien{ 994130561Sobrien struct elf_link_hash_table *htab; 99589857Sobrien struct eh_frame_hdr_info *hdr_info; 996130561Sobrien asection *sec; 99789857Sobrien 998130561Sobrien htab = elf_hash_table (info); 999130561Sobrien hdr_info = &htab->eh_info; 1000218822Sdim 1001218822Sdim if (hdr_info->cies != NULL) 1002218822Sdim { 1003218822Sdim htab_delete (hdr_info->cies); 1004218822Sdim hdr_info->cies = NULL; 1005218822Sdim } 1006218822Sdim 1007130561Sobrien sec = hdr_info->hdr_sec; 1008130561Sobrien if (sec == NULL) 1009130561Sobrien return FALSE; 101089857Sobrien 1011218822Sdim sec->size = EH_FRAME_HDR_SIZE; 101289857Sobrien if (hdr_info->table) 1013218822Sdim sec->size += 4 + hdr_info->fde_count * 8; 101489857Sobrien 1015130561Sobrien elf_tdata (abfd)->eh_frame_hdr = sec; 1016130561Sobrien return TRUE; 101789857Sobrien} 101889857Sobrien 101989857Sobrien/* This function is called from size_dynamic_sections. 102089857Sobrien It needs to decide whether .eh_frame_hdr should be output or not, 1021218822Sdim because when the dynamic symbol table has been sized it is too late 1022218822Sdim to strip sections. */ 102389857Sobrien 1024130561Sobrienbfd_boolean 1025130561Sobrien_bfd_elf_maybe_strip_eh_frame_hdr (struct bfd_link_info *info) 102689857Sobrien{ 1027130561Sobrien asection *o; 102889857Sobrien bfd *abfd; 1029130561Sobrien struct elf_link_hash_table *htab; 103089857Sobrien struct eh_frame_hdr_info *hdr_info; 103189857Sobrien 1032130561Sobrien htab = elf_hash_table (info); 1033130561Sobrien hdr_info = &htab->eh_info; 1034130561Sobrien if (hdr_info->hdr_sec == NULL) 1035130561Sobrien return TRUE; 103689857Sobrien 1037130561Sobrien if (bfd_is_abs_section (hdr_info->hdr_sec->output_section)) 1038130561Sobrien { 1039130561Sobrien hdr_info->hdr_sec = NULL; 1040130561Sobrien return TRUE; 1041130561Sobrien } 104289857Sobrien 104389857Sobrien abfd = NULL; 104489857Sobrien if (info->eh_frame_hdr) 104589857Sobrien for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link_next) 104689857Sobrien { 104789857Sobrien /* Count only sections which have at least a single CIE or FDE. 104889857Sobrien There cannot be any CIE or FDE <= 8 bytes. */ 104989857Sobrien o = bfd_get_section_by_name (abfd, ".eh_frame"); 1050218822Sdim if (o && o->size > 8 && !bfd_is_abs_section (o->output_section)) 105189857Sobrien break; 105289857Sobrien } 105389857Sobrien 105489857Sobrien if (abfd == NULL) 105589857Sobrien { 1056218822Sdim hdr_info->hdr_sec->flags |= SEC_EXCLUDE; 1057130561Sobrien hdr_info->hdr_sec = NULL; 1058130561Sobrien return TRUE; 105989857Sobrien } 1060130561Sobrien 1061130561Sobrien hdr_info->table = TRUE; 1062130561Sobrien return TRUE; 106389857Sobrien} 106489857Sobrien 106589857Sobrien/* Adjust an address in the .eh_frame section. Given OFFSET within 106689857Sobrien SEC, this returns the new offset in the adjusted .eh_frame section, 106789857Sobrien or -1 if the address refers to a CIE/FDE which has been removed 106889857Sobrien or to offset with dynamic relocation which is no longer needed. */ 106989857Sobrien 107089857Sobrienbfd_vma 1071130561Sobrien_bfd_elf_eh_frame_section_offset (bfd *output_bfd ATTRIBUTE_UNUSED, 1072218822Sdim struct bfd_link_info *info, 1073130561Sobrien asection *sec, 1074130561Sobrien bfd_vma offset) 107589857Sobrien{ 107689857Sobrien struct eh_frame_sec_info *sec_info; 1077218822Sdim struct elf_link_hash_table *htab; 1078218822Sdim struct eh_frame_hdr_info *hdr_info; 107989857Sobrien unsigned int lo, hi, mid; 108089857Sobrien 1081130561Sobrien if (sec->sec_info_type != ELF_INFO_TYPE_EH_FRAME) 108289857Sobrien return offset; 1083130561Sobrien sec_info = elf_section_data (sec)->sec_info; 108489857Sobrien 1085218822Sdim if (offset >= sec->rawsize) 1086218822Sdim return offset - sec->rawsize + sec->size; 108789857Sobrien 1088218822Sdim htab = elf_hash_table (info); 1089218822Sdim hdr_info = &htab->eh_info; 1090218822Sdim if (hdr_info->offsets_adjusted) 1091218822Sdim offset += sec->output_offset; 1092218822Sdim 109389857Sobrien lo = 0; 109489857Sobrien hi = sec_info->count; 109589857Sobrien mid = 0; 109689857Sobrien while (lo < hi) 109789857Sobrien { 109889857Sobrien mid = (lo + hi) / 2; 109989857Sobrien if (offset < sec_info->entry[mid].offset) 110089857Sobrien hi = mid; 110189857Sobrien else if (offset 110289857Sobrien >= sec_info->entry[mid].offset + sec_info->entry[mid].size) 110389857Sobrien lo = mid + 1; 110489857Sobrien else 110589857Sobrien break; 110689857Sobrien } 110789857Sobrien 110889857Sobrien BFD_ASSERT (lo < hi); 110989857Sobrien 111089857Sobrien /* FDE or CIE was removed. */ 111189857Sobrien if (sec_info->entry[mid].removed) 111289857Sobrien return (bfd_vma) -1; 111389857Sobrien 111489857Sobrien /* If converting to DW_EH_PE_pcrel, there will be no need for run-time 111589857Sobrien relocation against FDE's initial_location field. */ 1116218822Sdim if (!sec_info->entry[mid].cie 1117218822Sdim && sec_info->entry[mid].cie_inf->make_relative 111889857Sobrien && offset == sec_info->entry[mid].offset + 8) 111991041Sobrien return (bfd_vma) -2; 112089857Sobrien 112189857Sobrien /* If converting LSDA pointers to DW_EH_PE_pcrel, there will be no need 112289857Sobrien for run-time relocation against LSDA field. */ 1123218822Sdim if (!sec_info->entry[mid].cie 1124218822Sdim && sec_info->entry[mid].cie_inf->make_lsda_relative 1125130561Sobrien && (offset == (sec_info->entry[mid].offset + 8 1126218822Sdim + sec_info->entry[mid].lsda_offset)) 1127218822Sdim && (sec_info->entry[mid].cie_inf->need_lsda_relative 1128218822Sdim || !hdr_info->offsets_adjusted)) 1129218822Sdim { 1130218822Sdim sec_info->entry[mid].cie_inf->need_lsda_relative = 1; 1131218822Sdim return (bfd_vma) -2; 1132218822Sdim } 113389857Sobrien 1134218822Sdim /* If converting to DW_EH_PE_pcrel, there will be no need for run-time 1135218822Sdim relocation against DW_CFA_set_loc's arguments. */ 1136218822Sdim if (sec_info->entry[mid].set_loc 1137218822Sdim && (sec_info->entry[mid].cie 1138218822Sdim ? sec_info->entry[mid].make_relative 1139218822Sdim : sec_info->entry[mid].cie_inf->make_relative) 1140218822Sdim && (offset >= sec_info->entry[mid].offset + 8 1141218822Sdim + sec_info->entry[mid].set_loc[1])) 1142218822Sdim { 1143218822Sdim unsigned int cnt; 1144218822Sdim 1145218822Sdim for (cnt = 1; cnt <= sec_info->entry[mid].set_loc[0]; cnt++) 1146218822Sdim if (offset == sec_info->entry[mid].offset + 8 1147218822Sdim + sec_info->entry[mid].set_loc[cnt]) 1148218822Sdim return (bfd_vma) -2; 1149218822Sdim } 1150218822Sdim 1151218822Sdim if (hdr_info->offsets_adjusted) 1152218822Sdim offset -= sec->output_offset; 1153218822Sdim /* Any new augmentation bytes go before the first relocation. */ 115489857Sobrien return (offset + sec_info->entry[mid].new_offset 1155218822Sdim - sec_info->entry[mid].offset 1156218822Sdim + extra_augmentation_string_bytes (sec_info->entry + mid) 1157218822Sdim + extra_augmentation_data_bytes (sec_info->entry + mid)); 115889857Sobrien} 115989857Sobrien 116089857Sobrien/* Write out .eh_frame section. This is called with the relocated 116189857Sobrien contents. */ 116289857Sobrien 1163130561Sobrienbfd_boolean 1164130561Sobrien_bfd_elf_write_section_eh_frame (bfd *abfd, 1165130561Sobrien struct bfd_link_info *info, 1166130561Sobrien asection *sec, 1167130561Sobrien bfd_byte *contents) 116889857Sobrien{ 116989857Sobrien struct eh_frame_sec_info *sec_info; 1170130561Sobrien struct elf_link_hash_table *htab; 117189857Sobrien struct eh_frame_hdr_info *hdr_info; 117289857Sobrien unsigned int ptr_size; 1173218822Sdim struct eh_cie_fde *ent; 117489857Sobrien 1175130561Sobrien if (sec->sec_info_type != ELF_INFO_TYPE_EH_FRAME) 1176130561Sobrien return bfd_set_section_contents (abfd, sec->output_section, contents, 1177218822Sdim sec->output_offset, sec->size); 1178218822Sdim 1179218822Sdim ptr_size = (get_elf_backend_data (abfd) 1180218822Sdim ->elf_backend_eh_frame_address_size (abfd, sec)); 1181218822Sdim BFD_ASSERT (ptr_size != 0); 1182218822Sdim 1183130561Sobrien sec_info = elf_section_data (sec)->sec_info; 1184130561Sobrien htab = elf_hash_table (info); 1185130561Sobrien hdr_info = &htab->eh_info; 1186218822Sdim 1187218822Sdim /* First convert all offsets to output section offsets, so that a 1188218822Sdim CIE offset is valid if the CIE is used by a FDE from some other 1189218822Sdim section. This can happen when duplicate CIEs are deleted in 1190218822Sdim _bfd_elf_discard_section_eh_frame. We do all sections here because 1191218822Sdim this function might not be called on sections in the same order as 1192218822Sdim _bfd_elf_discard_section_eh_frame. */ 1193218822Sdim if (!hdr_info->offsets_adjusted) 1194218822Sdim { 1195218822Sdim bfd *ibfd; 1196218822Sdim asection *eh; 1197218822Sdim struct eh_frame_sec_info *eh_inf; 1198218822Sdim 1199218822Sdim for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) 1200218822Sdim { 1201218822Sdim if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour 1202218822Sdim || (ibfd->flags & DYNAMIC) != 0) 1203218822Sdim continue; 1204218822Sdim 1205218822Sdim eh = bfd_get_section_by_name (ibfd, ".eh_frame"); 1206218822Sdim if (eh == NULL || eh->sec_info_type != ELF_INFO_TYPE_EH_FRAME) 1207218822Sdim continue; 1208218822Sdim 1209218822Sdim eh_inf = elf_section_data (eh)->sec_info; 1210218822Sdim for (ent = eh_inf->entry; ent < eh_inf->entry + eh_inf->count; ++ent) 1211218822Sdim { 1212218822Sdim ent->offset += eh->output_offset; 1213218822Sdim ent->new_offset += eh->output_offset; 1214218822Sdim } 1215218822Sdim } 1216218822Sdim hdr_info->offsets_adjusted = TRUE; 1217218822Sdim } 1218218822Sdim 1219130561Sobrien if (hdr_info->table && hdr_info->array == NULL) 1220130561Sobrien hdr_info->array 1221130561Sobrien = bfd_malloc (hdr_info->fde_count * sizeof(*hdr_info->array)); 1222130561Sobrien if (hdr_info->array == NULL) 1223130561Sobrien hdr_info = NULL; 122489857Sobrien 1225218822Sdim /* The new offsets can be bigger or smaller than the original offsets. 1226218822Sdim We therefore need to make two passes over the section: one backward 1227218822Sdim pass to move entries up and one forward pass to move entries down. 1228218822Sdim The two passes won't interfere with each other because entries are 1229218822Sdim not reordered */ 1230218822Sdim for (ent = sec_info->entry + sec_info->count; ent-- != sec_info->entry;) 1231218822Sdim if (!ent->removed && ent->new_offset > ent->offset) 1232218822Sdim memmove (contents + ent->new_offset - sec->output_offset, 1233218822Sdim contents + ent->offset - sec->output_offset, ent->size); 1234218822Sdim 1235218822Sdim for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent) 1236218822Sdim if (!ent->removed && ent->new_offset < ent->offset) 1237218822Sdim memmove (contents + ent->new_offset - sec->output_offset, 1238218822Sdim contents + ent->offset - sec->output_offset, ent->size); 1239218822Sdim 1240218822Sdim for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent) 124189857Sobrien { 1242218822Sdim unsigned char *buf, *end; 1243218822Sdim unsigned int new_size; 1244218822Sdim 1245218822Sdim if (ent->removed) 1246218822Sdim continue; 1247218822Sdim 1248218822Sdim if (ent->size == 4) 124989857Sobrien { 1250218822Sdim /* Any terminating FDE must be at the end of the section. */ 1251218822Sdim BFD_ASSERT (ent == sec_info->entry + sec_info->count - 1); 125289857Sobrien continue; 125389857Sobrien } 125489857Sobrien 1255218822Sdim buf = contents + ent->new_offset - sec->output_offset; 1256218822Sdim end = buf + ent->size; 1257218822Sdim new_size = size_of_output_cie_fde (ent, ptr_size); 1258218822Sdim 1259218822Sdim /* Update the size. It may be shrinked. */ 1260218822Sdim bfd_put_32 (abfd, new_size - 4, buf); 1261218822Sdim 1262218822Sdim /* Filling the extra bytes with DW_CFA_nops. */ 1263218822Sdim if (new_size != ent->size) 1264218822Sdim memset (end, 0, new_size - ent->size); 1265218822Sdim 1266218822Sdim if (ent->cie) 126789857Sobrien { 126889857Sobrien /* CIE */ 1269218822Sdim if (ent->make_relative 1270218822Sdim || ent->need_lsda_relative 1271218822Sdim || ent->per_encoding_relative) 127289857Sobrien { 1273218822Sdim char *aug; 1274218822Sdim unsigned int action, extra_string, extra_data; 1275218822Sdim unsigned int per_width, per_encoding; 127689857Sobrien 127789857Sobrien /* Need to find 'R' or 'L' augmentation's argument and modify 127889857Sobrien DW_EH_PE_* value. */ 1279218822Sdim action = ((ent->make_relative ? 1 : 0) 1280218822Sdim | (ent->need_lsda_relative ? 2 : 0) 1281218822Sdim | (ent->per_encoding_relative ? 4 : 0)); 1282218822Sdim extra_string = extra_augmentation_string_bytes (ent); 1283218822Sdim extra_data = extra_augmentation_data_bytes (ent); 1284218822Sdim 128589857Sobrien /* Skip length, id and version. */ 128689857Sobrien buf += 9; 1287218822Sdim aug = (char *) buf; 1288218822Sdim buf += strlen (aug) + 1; 1289218822Sdim skip_leb128 (&buf, end); 1290218822Sdim skip_leb128 (&buf, end); 1291218822Sdim skip_leb128 (&buf, end); 129289857Sobrien if (*aug == 'z') 129389857Sobrien { 1294218822Sdim /* The uleb128 will always be a single byte for the kind 1295218822Sdim of augmentation strings that we're prepared to handle. */ 1296218822Sdim *buf++ += extra_data; 129789857Sobrien aug++; 129889857Sobrien } 129989857Sobrien 1300218822Sdim /* Make room for the new augmentation string and data bytes. */ 1301218822Sdim memmove (buf + extra_string + extra_data, buf, end - buf); 1302218822Sdim memmove (aug + extra_string, aug, buf - (bfd_byte *) aug); 1303218822Sdim buf += extra_string; 1304218822Sdim end += extra_string + extra_data; 1305218822Sdim 1306218822Sdim if (ent->add_augmentation_size) 1307218822Sdim { 1308218822Sdim *aug++ = 'z'; 1309218822Sdim *buf++ = extra_data - 1; 1310218822Sdim } 1311218822Sdim if (ent->add_fde_encoding) 1312218822Sdim { 1313218822Sdim BFD_ASSERT (action & 1); 1314218822Sdim *aug++ = 'R'; 1315218822Sdim *buf++ = DW_EH_PE_pcrel; 1316218822Sdim action &= ~1; 1317218822Sdim } 1318218822Sdim 131989857Sobrien while (action) 132089857Sobrien switch (*aug++) 132189857Sobrien { 132289857Sobrien case 'L': 132389857Sobrien if (action & 2) 132489857Sobrien { 1325218822Sdim BFD_ASSERT (*buf == ent->lsda_encoding); 132689857Sobrien *buf |= DW_EH_PE_pcrel; 132789857Sobrien action &= ~2; 132889857Sobrien } 132989857Sobrien buf++; 133089857Sobrien break; 133189857Sobrien case 'P': 133289857Sobrien per_encoding = *buf++; 1333218822Sdim per_width = get_DW_EH_PE_width (per_encoding, ptr_size); 133489857Sobrien BFD_ASSERT (per_width != 0); 133599461Sobrien BFD_ASSERT (((per_encoding & 0x70) == DW_EH_PE_pcrel) 1336218822Sdim == ent->per_encoding_relative); 133789857Sobrien if ((per_encoding & 0xf0) == DW_EH_PE_aligned) 133889857Sobrien buf = (contents 133989857Sobrien + ((buf - contents + per_width - 1) 134089857Sobrien & ~((bfd_size_type) per_width - 1))); 134199461Sobrien if (action & 4) 134299461Sobrien { 1343218822Sdim bfd_vma val; 134499461Sobrien 1345218822Sdim val = read_value (abfd, buf, per_width, 1346218822Sdim get_DW_EH_PE_signed (per_encoding)); 1347218822Sdim val += ent->offset - ent->new_offset; 1348218822Sdim val -= extra_string + extra_data; 1349218822Sdim write_value (abfd, buf, val, per_width); 135099461Sobrien action &= ~4; 135199461Sobrien } 135289857Sobrien buf += per_width; 135389857Sobrien break; 135489857Sobrien case 'R': 135589857Sobrien if (action & 1) 135689857Sobrien { 1357218822Sdim BFD_ASSERT (*buf == ent->fde_encoding); 135889857Sobrien *buf |= DW_EH_PE_pcrel; 135989857Sobrien action &= ~1; 136089857Sobrien } 136189857Sobrien buf++; 136289857Sobrien break; 1363218822Sdim case 'S': 1364218822Sdim break; 136589857Sobrien default: 136689857Sobrien BFD_FAIL (); 136789857Sobrien } 136889857Sobrien } 136989857Sobrien } 1370218822Sdim else 137189857Sobrien { 137289857Sobrien /* FDE */ 1373218822Sdim bfd_vma value, address; 137489857Sobrien unsigned int width; 1375218822Sdim bfd_byte *start; 137689857Sobrien 1377130561Sobrien /* Skip length. */ 137889857Sobrien buf += 4; 1379218822Sdim value = ent->new_offset + 4 - ent->cie_inf->new_offset; 1380218822Sdim bfd_put_32 (abfd, value, buf); 138189857Sobrien buf += 4; 1382218822Sdim width = get_DW_EH_PE_width (ent->fde_encoding, ptr_size); 1383218822Sdim value = read_value (abfd, buf, width, 1384218822Sdim get_DW_EH_PE_signed (ent->fde_encoding)); 1385218822Sdim address = value; 138689857Sobrien if (value) 138789857Sobrien { 1388218822Sdim switch (ent->fde_encoding & 0xf0) 138989857Sobrien { 139089857Sobrien case DW_EH_PE_indirect: 139189857Sobrien case DW_EH_PE_textrel: 139289857Sobrien BFD_ASSERT (hdr_info == NULL); 139389857Sobrien break; 139489857Sobrien case DW_EH_PE_datarel: 139589857Sobrien { 139689857Sobrien asection *got = bfd_get_section_by_name (abfd, ".got"); 139789857Sobrien 139889857Sobrien BFD_ASSERT (got != NULL); 139989857Sobrien address += got->vma; 140089857Sobrien } 140189857Sobrien break; 140289857Sobrien case DW_EH_PE_pcrel: 1403218822Sdim value += ent->offset - ent->new_offset; 1404218822Sdim address += sec->output_section->vma + ent->offset + 8; 140589857Sobrien break; 140689857Sobrien } 1407218822Sdim if (ent->cie_inf->make_relative) 1408218822Sdim value -= sec->output_section->vma + ent->new_offset + 8; 140989857Sobrien write_value (abfd, buf, value, width); 141089857Sobrien } 141189857Sobrien 1412218822Sdim start = buf; 1413218822Sdim 141489857Sobrien if (hdr_info) 141589857Sobrien { 141689857Sobrien hdr_info->array[hdr_info->array_count].initial_loc = address; 141789857Sobrien hdr_info->array[hdr_info->array_count++].fde 1418218822Sdim = sec->output_section->vma + ent->new_offset; 141989857Sobrien } 142089857Sobrien 1421218822Sdim if ((ent->lsda_encoding & 0xf0) == DW_EH_PE_pcrel 1422218822Sdim || ent->cie_inf->need_lsda_relative) 142389857Sobrien { 1424218822Sdim buf += ent->lsda_offset; 1425218822Sdim width = get_DW_EH_PE_width (ent->lsda_encoding, ptr_size); 1426130561Sobrien value = read_value (abfd, buf, width, 1427218822Sdim get_DW_EH_PE_signed (ent->lsda_encoding)); 142889857Sobrien if (value) 142989857Sobrien { 1430218822Sdim if ((ent->lsda_encoding & 0xf0) == DW_EH_PE_pcrel) 1431218822Sdim value += ent->offset - ent->new_offset; 1432218822Sdim else if (ent->cie_inf->need_lsda_relative) 1433218822Sdim value -= (sec->output_section->vma + ent->new_offset + 8 1434218822Sdim + ent->lsda_offset); 143589857Sobrien write_value (abfd, buf, value, width); 143689857Sobrien } 143789857Sobrien } 1438218822Sdim else if (ent->cie_inf->add_augmentation_size) 1439218822Sdim { 1440218822Sdim /* Skip the PC and length and insert a zero byte for the 1441218822Sdim augmentation size. */ 1442218822Sdim buf += width * 2; 1443218822Sdim memmove (buf + 1, buf, end - buf); 1444218822Sdim *buf = 0; 1445218822Sdim } 144689857Sobrien 1447218822Sdim if (ent->set_loc) 1448218822Sdim { 1449218822Sdim /* Adjust DW_CFA_set_loc. */ 1450218822Sdim unsigned int cnt, width; 1451218822Sdim bfd_vma new_offset; 145289857Sobrien 1453218822Sdim width = get_DW_EH_PE_width (ent->fde_encoding, ptr_size); 1454218822Sdim new_offset = ent->new_offset + 8 1455218822Sdim + extra_augmentation_string_bytes (ent) 1456218822Sdim + extra_augmentation_data_bytes (ent); 145789857Sobrien 1458218822Sdim for (cnt = 1; cnt <= ent->set_loc[0]; cnt++) 1459218822Sdim { 1460218822Sdim bfd_vma value; 1461218822Sdim buf = start + ent->set_loc[cnt]; 1462130561Sobrien 1463218822Sdim value = read_value (abfd, buf, width, 1464218822Sdim get_DW_EH_PE_signed (ent->fde_encoding)); 1465218822Sdim if (!value) 1466218822Sdim continue; 1467130561Sobrien 1468218822Sdim if ((ent->fde_encoding & 0xf0) == DW_EH_PE_pcrel) 1469218822Sdim value += ent->offset + 8 - new_offset; 1470218822Sdim if (ent->cie_inf->make_relative) 1471218822Sdim value -= sec->output_section->vma + new_offset 1472218822Sdim + ent->set_loc[cnt]; 1473218822Sdim write_value (abfd, buf, value, width); 1474218822Sdim } 1475218822Sdim } 1476130561Sobrien } 1477130561Sobrien } 1478130561Sobrien 1479218822Sdim /* We don't align the section to its section alignment since the 1480218822Sdim runtime library only expects all CIE/FDE records aligned at 1481218822Sdim the pointer size. _bfd_elf_discard_section_eh_frame should 1482218822Sdim have padded CIE/FDE records to multiple of pointer size with 1483218822Sdim size_of_output_cie_fde. */ 1484218822Sdim if ((sec->size % ptr_size) != 0) 1485218822Sdim abort (); 148689857Sobrien 148789857Sobrien return bfd_set_section_contents (abfd, sec->output_section, 1488218822Sdim contents, (file_ptr) sec->output_offset, 1489218822Sdim sec->size); 149089857Sobrien} 149189857Sobrien 149289857Sobrien/* Helper function used to sort .eh_frame_hdr search table by increasing 149389857Sobrien VMA of FDE initial location. */ 149489857Sobrien 149589857Sobrienstatic int 1496130561Sobrienvma_compare (const void *a, const void *b) 149789857Sobrien{ 1498130561Sobrien const struct eh_frame_array_ent *p = a; 1499130561Sobrien const struct eh_frame_array_ent *q = b; 150089857Sobrien if (p->initial_loc > q->initial_loc) 150189857Sobrien return 1; 150289857Sobrien if (p->initial_loc < q->initial_loc) 150389857Sobrien return -1; 150489857Sobrien return 0; 150589857Sobrien} 150689857Sobrien 150789857Sobrien/* Write out .eh_frame_hdr section. This must be called after 150889857Sobrien _bfd_elf_write_section_eh_frame has been called on all input 150989857Sobrien .eh_frame sections. 151089857Sobrien .eh_frame_hdr format: 151189857Sobrien ubyte version (currently 1) 151289857Sobrien ubyte eh_frame_ptr_enc (DW_EH_PE_* encoding of pointer to start of 151389857Sobrien .eh_frame section) 151489857Sobrien ubyte fde_count_enc (DW_EH_PE_* encoding of total FDE count 151589857Sobrien number (or DW_EH_PE_omit if there is no 151689857Sobrien binary search table computed)) 151789857Sobrien ubyte table_enc (DW_EH_PE_* encoding of binary search table, 151889857Sobrien or DW_EH_PE_omit if not present. 151989857Sobrien DW_EH_PE_datarel is using address of 152089857Sobrien .eh_frame_hdr section start as base) 152189857Sobrien [encoded] eh_frame_ptr (pointer to start of .eh_frame section) 152289857Sobrien optionally followed by: 152389857Sobrien [encoded] fde_count (total number of FDEs in .eh_frame section) 152489857Sobrien fde_count x [encoded] initial_loc, fde 152589857Sobrien (array of encoded pairs containing 152689857Sobrien FDE initial_location field and FDE address, 1527130561Sobrien sorted by increasing initial_loc). */ 152889857Sobrien 1529130561Sobrienbfd_boolean 1530130561Sobrien_bfd_elf_write_section_eh_frame_hdr (bfd *abfd, struct bfd_link_info *info) 153189857Sobrien{ 1532130561Sobrien struct elf_link_hash_table *htab; 153389857Sobrien struct eh_frame_hdr_info *hdr_info; 1534130561Sobrien asection *sec; 153589857Sobrien bfd_byte *contents; 153689857Sobrien asection *eh_frame_sec; 153789857Sobrien bfd_size_type size; 1538130561Sobrien bfd_boolean retval; 1539130561Sobrien bfd_vma encoded_eh_frame; 154089857Sobrien 1541130561Sobrien htab = elf_hash_table (info); 1542130561Sobrien hdr_info = &htab->eh_info; 1543130561Sobrien sec = hdr_info->hdr_sec; 1544130561Sobrien if (sec == NULL) 1545130561Sobrien return TRUE; 154689857Sobrien 154789857Sobrien size = EH_FRAME_HDR_SIZE; 154889857Sobrien if (hdr_info->array && hdr_info->array_count == hdr_info->fde_count) 154989857Sobrien size += 4 + hdr_info->fde_count * 8; 155089857Sobrien contents = bfd_malloc (size); 155189857Sobrien if (contents == NULL) 1552130561Sobrien return FALSE; 155389857Sobrien 155489857Sobrien eh_frame_sec = bfd_get_section_by_name (abfd, ".eh_frame"); 155589857Sobrien if (eh_frame_sec == NULL) 1556130561Sobrien { 1557130561Sobrien free (contents); 1558130561Sobrien return FALSE; 1559130561Sobrien } 156089857Sobrien 156189857Sobrien memset (contents, 0, EH_FRAME_HDR_SIZE); 1562130561Sobrien contents[0] = 1; /* Version. */ 1563130561Sobrien contents[1] = get_elf_backend_data (abfd)->elf_backend_encode_eh_address 1564130561Sobrien (abfd, info, eh_frame_sec, 0, sec, 4, 1565130561Sobrien &encoded_eh_frame); /* .eh_frame offset. */ 1566130561Sobrien 156789857Sobrien if (hdr_info->array && hdr_info->array_count == hdr_info->fde_count) 156889857Sobrien { 1569130561Sobrien contents[2] = DW_EH_PE_udata4; /* FDE count encoding. */ 1570130561Sobrien contents[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4; /* Search table enc. */ 157189857Sobrien } 157289857Sobrien else 157389857Sobrien { 157489857Sobrien contents[2] = DW_EH_PE_omit; 157589857Sobrien contents[3] = DW_EH_PE_omit; 157689857Sobrien } 1577130561Sobrien bfd_put_32 (abfd, encoded_eh_frame, contents + 4); 1578130561Sobrien 157989857Sobrien if (contents[2] != DW_EH_PE_omit) 158089857Sobrien { 158189857Sobrien unsigned int i; 158289857Sobrien 158389857Sobrien bfd_put_32 (abfd, hdr_info->fde_count, contents + EH_FRAME_HDR_SIZE); 158489857Sobrien qsort (hdr_info->array, hdr_info->fde_count, sizeof (*hdr_info->array), 158589857Sobrien vma_compare); 158689857Sobrien for (i = 0; i < hdr_info->fde_count; i++) 158789857Sobrien { 158889857Sobrien bfd_put_32 (abfd, 158989857Sobrien hdr_info->array[i].initial_loc 159089857Sobrien - sec->output_section->vma, 159189857Sobrien contents + EH_FRAME_HDR_SIZE + i * 8 + 4); 159289857Sobrien bfd_put_32 (abfd, 159389857Sobrien hdr_info->array[i].fde - sec->output_section->vma, 159489857Sobrien contents + EH_FRAME_HDR_SIZE + i * 8 + 8); 159589857Sobrien } 159689857Sobrien } 159789857Sobrien 1598130561Sobrien retval = bfd_set_section_contents (abfd, sec->output_section, 1599130561Sobrien contents, (file_ptr) sec->output_offset, 1600218822Sdim sec->size); 1601130561Sobrien free (contents); 1602130561Sobrien return retval; 160389857Sobrien} 1604130561Sobrien 1605218822Sdim/* Return the width of FDE addresses. This is the default implementation. */ 1606218822Sdim 1607218822Sdimunsigned int 1608218822Sdim_bfd_elf_eh_frame_address_size (bfd *abfd, asection *sec ATTRIBUTE_UNUSED) 1609218822Sdim{ 1610218822Sdim return elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64 ? 8 : 4; 1611218822Sdim} 1612218822Sdim 1613130561Sobrien/* Decide whether we can use a PC-relative encoding within the given 1614130561Sobrien EH frame section. This is the default implementation. */ 1615130561Sobrien 1616130561Sobrienbfd_boolean 1617130561Sobrien_bfd_elf_can_make_relative (bfd *input_bfd ATTRIBUTE_UNUSED, 1618130561Sobrien struct bfd_link_info *info ATTRIBUTE_UNUSED, 1619130561Sobrien asection *eh_frame_section ATTRIBUTE_UNUSED) 1620130561Sobrien{ 1621130561Sobrien return TRUE; 1622130561Sobrien} 1623130561Sobrien 1624130561Sobrien/* Select an encoding for the given address. Preference is given to 1625130561Sobrien PC-relative addressing modes. */ 1626130561Sobrien 1627130561Sobrienbfd_byte 1628130561Sobrien_bfd_elf_encode_eh_address (bfd *abfd ATTRIBUTE_UNUSED, 1629130561Sobrien struct bfd_link_info *info ATTRIBUTE_UNUSED, 1630130561Sobrien asection *osec, bfd_vma offset, 1631130561Sobrien asection *loc_sec, bfd_vma loc_offset, 1632130561Sobrien bfd_vma *encoded) 1633130561Sobrien{ 1634130561Sobrien *encoded = osec->vma + offset - 1635130561Sobrien (loc_sec->output_section->vma + loc_sec->output_offset + loc_offset); 1636130561Sobrien return DW_EH_PE_pcrel | DW_EH_PE_sdata4; 1637130561Sobrien} 1638