2007-09-26 13:44:38 +08:00
|
|
|
// ehframe.cc -- handle exception frame sections for gold
|
|
|
|
|
2021-01-01 06:58:58 +08:00
|
|
|
// Copyright (C) 2006-2021 Free Software Foundation, Inc.
|
2007-09-26 13:44:38 +08:00
|
|
|
// Written by Ian Lance Taylor <iant@google.com>.
|
|
|
|
|
|
|
|
// This file is part of gold.
|
|
|
|
|
|
|
|
// This program is free software; you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation; either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with this program; if not, write to the Free Software
|
|
|
|
// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
|
|
|
// MA 02110-1301, USA.
|
|
|
|
|
|
|
|
#include "gold.h"
|
|
|
|
|
2007-11-09 15:00:15 +08:00
|
|
|
#include <cstring>
|
|
|
|
#include <algorithm>
|
|
|
|
|
2007-09-26 13:44:38 +08:00
|
|
|
#include "elfcpp.h"
|
|
|
|
#include "dwarf.h"
|
2007-11-09 15:00:15 +08:00
|
|
|
#include "symtab.h"
|
|
|
|
#include "reloc.h"
|
2007-09-26 13:44:38 +08:00
|
|
|
#include "ehframe.h"
|
|
|
|
|
|
|
|
namespace gold
|
|
|
|
{
|
|
|
|
|
|
|
|
// This file handles generation of the exception frame header that
|
|
|
|
// gcc's runtime support libraries use to find unwind information at
|
2007-11-09 15:00:15 +08:00
|
|
|
// runtime. This file also handles discarding duplicate exception
|
|
|
|
// frame information.
|
2007-09-26 13:44:38 +08:00
|
|
|
|
|
|
|
// The exception frame header starts with four bytes:
|
|
|
|
|
|
|
|
// 0: The version number, currently 1.
|
|
|
|
|
|
|
|
// 1: The encoding of the pointer to the exception frames. This can
|
|
|
|
// be any DWARF unwind encoding (DW_EH_PE_*). It is normally a 4
|
|
|
|
// byte PC relative offset (DW_EH_PE_pcrel | DW_EH_PE_sdata4).
|
|
|
|
|
|
|
|
// 2: The encoding of the count of the number of FDE pointers in the
|
|
|
|
// lookup table. This can be any DWARF unwind encoding, and in
|
|
|
|
// particular can be DW_EH_PE_omit if the count is omitted. It is
|
|
|
|
// normally a 4 byte unsigned count (DW_EH_PE_udata4).
|
|
|
|
|
|
|
|
// 3: The encoding of the lookup table entries. Currently gcc's
|
|
|
|
// libraries will only support DW_EH_PE_datarel | DW_EH_PE_sdata4,
|
|
|
|
// which means that the values are 4 byte offsets from the start of
|
|
|
|
// the table.
|
|
|
|
|
|
|
|
// The exception frame header is followed by a pointer to the contents
|
|
|
|
// of the exception frame section (.eh_frame). This pointer is
|
|
|
|
// encoded as specified in the byte at offset 1 of the header (i.e.,
|
|
|
|
// it is normally a 4 byte PC relative offset).
|
|
|
|
|
|
|
|
// If there is a lookup table, this is followed by the count of the
|
|
|
|
// number of FDE pointers, encoded as specified in the byte at offset
|
|
|
|
// 2 of the header (i.e., normally a 4 byte unsigned integer).
|
|
|
|
|
|
|
|
// This is followed by the table, which should start at an 4-byte
|
|
|
|
// aligned address in memory. Each entry in the table is 8 bytes.
|
|
|
|
// Each entry represents an FDE. The first four bytes of each entry
|
|
|
|
// are an offset to the starting PC for the FDE. The last four bytes
|
|
|
|
// of each entry are an offset to the FDE data. The offsets are from
|
|
|
|
// the start of the exception frame header information. The entries
|
|
|
|
// are in sorted order by starting PC.
|
|
|
|
|
|
|
|
const int eh_frame_hdr_size = 4;
|
|
|
|
|
|
|
|
// Construct the exception frame header.
|
|
|
|
|
2007-11-09 15:00:15 +08:00
|
|
|
Eh_frame_hdr::Eh_frame_hdr(Output_section* eh_frame_section,
|
|
|
|
const Eh_frame* eh_frame_data)
|
2007-09-26 13:44:38 +08:00
|
|
|
: Output_section_data(4),
|
2007-11-09 15:00:15 +08:00
|
|
|
eh_frame_section_(eh_frame_section),
|
|
|
|
eh_frame_data_(eh_frame_data),
|
|
|
|
fde_offsets_(),
|
2013-11-15 05:15:06 +08:00
|
|
|
any_unrecognized_eh_frame_sections_(false)
|
2007-09-26 13:44:38 +08:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2007-11-30 04:10:17 +08:00
|
|
|
// Set the size of the exception frame header.
|
2007-09-26 13:44:38 +08:00
|
|
|
|
|
|
|
void
|
2007-11-30 04:10:17 +08:00
|
|
|
Eh_frame_hdr::set_final_data_size()
|
2007-09-26 13:44:38 +08:00
|
|
|
{
|
2009-12-15 03:53:05 +08:00
|
|
|
unsigned int data_size = eh_frame_hdr_size + 4;
|
2007-11-09 15:00:15 +08:00
|
|
|
if (!this->any_unrecognized_eh_frame_sections_)
|
|
|
|
{
|
|
|
|
unsigned int fde_count = this->eh_frame_data_->fde_count();
|
|
|
|
if (fde_count != 0)
|
2009-12-15 03:53:05 +08:00
|
|
|
data_size += 4 + 8 * fde_count;
|
2007-11-09 15:00:15 +08:00
|
|
|
this->fde_offsets_.reserve(fde_count);
|
|
|
|
}
|
2009-12-15 03:53:05 +08:00
|
|
|
this->set_data_size(data_size);
|
2007-09-26 13:44:38 +08:00
|
|
|
}
|
|
|
|
|
2010-12-15 03:03:30 +08:00
|
|
|
// Write the data to the file.
|
2007-09-26 13:44:38 +08:00
|
|
|
|
|
|
|
void
|
|
|
|
Eh_frame_hdr::do_write(Output_file* of)
|
2007-11-09 15:00:15 +08:00
|
|
|
{
|
2008-02-28 08:18:24 +08:00
|
|
|
switch (parameters->size_and_endianness())
|
2007-11-09 15:00:15 +08:00
|
|
|
{
|
|
|
|
#ifdef HAVE_TARGET_32_LITTLE
|
2008-02-28 08:18:24 +08:00
|
|
|
case Parameters::TARGET_32_LITTLE:
|
|
|
|
this->do_sized_write<32, false>(of);
|
|
|
|
break;
|
2007-11-09 15:00:15 +08:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_TARGET_32_BIG
|
2008-02-28 08:18:24 +08:00
|
|
|
case Parameters::TARGET_32_BIG:
|
|
|
|
this->do_sized_write<32, true>(of);
|
|
|
|
break;
|
2007-11-09 15:00:15 +08:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_TARGET_64_LITTLE
|
2008-02-28 08:18:24 +08:00
|
|
|
case Parameters::TARGET_64_LITTLE:
|
|
|
|
this->do_sized_write<64, false>(of);
|
|
|
|
break;
|
2007-11-09 15:00:15 +08:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_TARGET_64_BIG
|
2008-02-28 08:18:24 +08:00
|
|
|
case Parameters::TARGET_64_BIG:
|
|
|
|
this->do_sized_write<64, true>(of);
|
|
|
|
break;
|
2007-11-09 15:00:15 +08:00
|
|
|
#endif
|
2008-02-28 08:18:24 +08:00
|
|
|
default:
|
|
|
|
gold_unreachable();
|
2007-11-09 15:00:15 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write the data to the file with the right endianness.
|
|
|
|
|
|
|
|
template<int size, bool big_endian>
|
|
|
|
void
|
|
|
|
Eh_frame_hdr::do_sized_write(Output_file* of)
|
2007-09-26 13:44:38 +08:00
|
|
|
{
|
|
|
|
const off_t off = this->offset();
|
|
|
|
const off_t oview_size = this->data_size();
|
|
|
|
unsigned char* const oview = of->get_output_view(off, oview_size);
|
|
|
|
|
|
|
|
// Version number.
|
|
|
|
oview[0] = 1;
|
|
|
|
|
|
|
|
// Write out a 4 byte PC relative offset to the address of the
|
|
|
|
// .eh_frame section.
|
|
|
|
oview[1] = elfcpp::DW_EH_PE_pcrel | elfcpp::DW_EH_PE_sdata4;
|
|
|
|
uint64_t eh_frame_address = this->eh_frame_section_->address();
|
|
|
|
uint64_t eh_frame_hdr_address = this->address();
|
|
|
|
uint64_t eh_frame_offset = (eh_frame_address -
|
|
|
|
(eh_frame_hdr_address + 4));
|
2007-11-09 15:00:15 +08:00
|
|
|
elfcpp::Swap<32, big_endian>::writeval(oview + 4, eh_frame_offset);
|
|
|
|
|
|
|
|
if (this->any_unrecognized_eh_frame_sections_
|
|
|
|
|| this->fde_offsets_.empty())
|
|
|
|
{
|
|
|
|
// There are no FDEs, or we didn't recognize the format of the
|
|
|
|
// some of the .eh_frame sections, so we can't write out the
|
|
|
|
// sorted table.
|
|
|
|
oview[2] = elfcpp::DW_EH_PE_omit;
|
|
|
|
oview[3] = elfcpp::DW_EH_PE_omit;
|
|
|
|
|
|
|
|
gold_assert(oview_size == 8);
|
|
|
|
}
|
2007-09-26 13:44:38 +08:00
|
|
|
else
|
2007-11-09 15:00:15 +08:00
|
|
|
{
|
|
|
|
oview[2] = elfcpp::DW_EH_PE_udata4;
|
|
|
|
oview[3] = elfcpp::DW_EH_PE_datarel | elfcpp::DW_EH_PE_sdata4;
|
|
|
|
|
|
|
|
elfcpp::Swap<32, big_endian>::writeval(oview + 8,
|
|
|
|
this->fde_offsets_.size());
|
|
|
|
|
|
|
|
// We have the offsets of the FDEs in the .eh_frame section. We
|
|
|
|
// couldn't easily get the PC values before, as they depend on
|
|
|
|
// relocations which are, of course, target specific. This code
|
|
|
|
// is run after all those relocations have been applied to the
|
|
|
|
// output file. Here we read the output file again to find the
|
|
|
|
// PC values. Then we sort the list and write it out.
|
2007-09-26 13:44:38 +08:00
|
|
|
|
2007-11-09 15:00:15 +08:00
|
|
|
Fde_addresses<size> fde_addresses(this->fde_offsets_.size());
|
|
|
|
this->get_fde_addresses<size, big_endian>(of, &this->fde_offsets_,
|
|
|
|
&fde_addresses);
|
2007-09-26 13:44:38 +08:00
|
|
|
|
2007-11-09 15:00:15 +08:00
|
|
|
std::sort(fde_addresses.begin(), fde_addresses.end(),
|
|
|
|
Fde_address_compare<size>());
|
|
|
|
|
|
|
|
typename elfcpp::Elf_types<size>::Elf_Addr output_address;
|
|
|
|
output_address = this->address();
|
|
|
|
|
|
|
|
unsigned char* pfde = oview + 12;
|
|
|
|
for (typename Fde_addresses<size>::iterator p = fde_addresses.begin();
|
|
|
|
p != fde_addresses.end();
|
|
|
|
++p)
|
|
|
|
{
|
|
|
|
elfcpp::Swap<32, big_endian>::writeval(pfde,
|
|
|
|
p->first - output_address);
|
|
|
|
elfcpp::Swap<32, big_endian>::writeval(pfde + 4,
|
|
|
|
p->second - output_address);
|
|
|
|
pfde += 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
gold_assert(pfde - oview == oview_size);
|
|
|
|
}
|
2007-09-26 13:44:38 +08:00
|
|
|
|
|
|
|
of->write_output_view(off, oview_size, oview);
|
|
|
|
}
|
|
|
|
|
2007-11-09 15:00:15 +08:00
|
|
|
// Given the offset FDE_OFFSET of an FDE in the .eh_frame section, and
|
|
|
|
// the contents of the .eh_frame section EH_FRAME_CONTENTS, where the
|
|
|
|
// FDE's encoding is FDE_ENCODING, return the output address of the
|
|
|
|
// FDE's PC.
|
|
|
|
|
|
|
|
template<int size, bool big_endian>
|
|
|
|
typename elfcpp::Elf_types<size>::Elf_Addr
|
2007-12-07 14:44:01 +08:00
|
|
|
Eh_frame_hdr::get_fde_pc(
|
|
|
|
typename elfcpp::Elf_types<size>::Elf_Addr eh_frame_address,
|
|
|
|
const unsigned char* eh_frame_contents,
|
2007-12-18 08:48:04 +08:00
|
|
|
section_offset_type fde_offset,
|
2007-12-07 14:44:01 +08:00
|
|
|
unsigned char fde_encoding)
|
2007-11-09 15:00:15 +08:00
|
|
|
{
|
|
|
|
// The FDE starts with a 4 byte length and a 4 byte offset to the
|
|
|
|
// CIE. The PC follows.
|
|
|
|
const unsigned char* p = eh_frame_contents + fde_offset + 8;
|
|
|
|
|
|
|
|
typename elfcpp::Elf_types<size>::Elf_Addr pc;
|
|
|
|
bool is_signed = (fde_encoding & elfcpp::DW_EH_PE_signed) != 0;
|
|
|
|
int pc_size = fde_encoding & 7;
|
|
|
|
if (pc_size == elfcpp::DW_EH_PE_absptr)
|
|
|
|
{
|
|
|
|
if (size == 32)
|
|
|
|
pc_size = elfcpp::DW_EH_PE_udata4;
|
|
|
|
else if (size == 64)
|
|
|
|
pc_size = elfcpp::DW_EH_PE_udata8;
|
|
|
|
else
|
|
|
|
gold_unreachable();
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (pc_size)
|
|
|
|
{
|
|
|
|
case elfcpp::DW_EH_PE_udata2:
|
|
|
|
pc = elfcpp::Swap<16, big_endian>::readval(p);
|
|
|
|
if (is_signed)
|
|
|
|
pc = (pc ^ 0x8000) - 0x8000;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case elfcpp::DW_EH_PE_udata4:
|
|
|
|
pc = elfcpp::Swap<32, big_endian>::readval(p);
|
|
|
|
if (size > 32 && is_signed)
|
|
|
|
pc = (pc ^ 0x80000000) - 0x80000000;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case elfcpp::DW_EH_PE_udata8:
|
|
|
|
gold_assert(size == 64);
|
|
|
|
pc = elfcpp::Swap_unaligned<64, big_endian>::readval(p);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2007-12-07 14:44:01 +08:00
|
|
|
// All other cases were rejected in Eh_frame::read_cie.
|
|
|
|
gold_unreachable();
|
|
|
|
}
|
|
|
|
|
2011-07-02 08:03:25 +08:00
|
|
|
switch (fde_encoding & 0x70)
|
2007-12-07 14:44:01 +08:00
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case elfcpp::DW_EH_PE_pcrel:
|
|
|
|
pc += eh_frame_address + fde_offset + 8;
|
|
|
|
break;
|
|
|
|
|
2011-07-02 08:03:25 +08:00
|
|
|
case elfcpp::DW_EH_PE_datarel:
|
|
|
|
pc += parameters->target().ehframe_datarel_base();
|
|
|
|
break;
|
|
|
|
|
2007-12-07 14:44:01 +08:00
|
|
|
default:
|
|
|
|
// If other cases arise, then we have to handle them, or we have
|
|
|
|
// to reject them by returning false in Eh_frame::read_cie.
|
2007-11-09 15:00:15 +08:00
|
|
|
gold_unreachable();
|
|
|
|
}
|
|
|
|
|
2011-07-02 08:03:25 +08:00
|
|
|
gold_assert((fde_encoding & elfcpp::DW_EH_PE_indirect) == 0);
|
|
|
|
|
2007-11-09 15:00:15 +08:00
|
|
|
return pc;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Given an array of FDE offsets in the .eh_frame section, return an
|
|
|
|
// array of offsets from the exception frame header to the FDE's
|
|
|
|
// output PC and to the output address of the FDE itself. We get the
|
|
|
|
// FDE's PC by actually looking in the .eh_frame section we just wrote
|
|
|
|
// to the output file.
|
|
|
|
|
|
|
|
template<int size, bool big_endian>
|
|
|
|
void
|
|
|
|
Eh_frame_hdr::get_fde_addresses(Output_file* of,
|
|
|
|
const Fde_offsets* fde_offsets,
|
|
|
|
Fde_addresses<size>* fde_addresses)
|
|
|
|
{
|
|
|
|
typename elfcpp::Elf_types<size>::Elf_Addr eh_frame_address;
|
|
|
|
eh_frame_address = this->eh_frame_section_->address();
|
|
|
|
off_t eh_frame_offset = this->eh_frame_section_->offset();
|
|
|
|
off_t eh_frame_size = this->eh_frame_section_->data_size();
|
|
|
|
const unsigned char* eh_frame_contents = of->get_input_view(eh_frame_offset,
|
|
|
|
eh_frame_size);
|
|
|
|
|
|
|
|
for (Fde_offsets::const_iterator p = fde_offsets->begin();
|
|
|
|
p != fde_offsets->end();
|
|
|
|
++p)
|
|
|
|
{
|
|
|
|
typename elfcpp::Elf_types<size>::Elf_Addr fde_pc;
|
2007-12-07 14:44:01 +08:00
|
|
|
fde_pc = this->get_fde_pc<size, big_endian>(eh_frame_address,
|
|
|
|
eh_frame_contents,
|
2007-11-09 15:00:15 +08:00
|
|
|
p->first, p->second);
|
|
|
|
fde_addresses->push_back(fde_pc, eh_frame_address + p->first);
|
|
|
|
}
|
|
|
|
|
|
|
|
of->free_input_view(eh_frame_offset, eh_frame_size, eh_frame_contents);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Class Fde.
|
|
|
|
|
|
|
|
// Write the FDE to OVIEW starting at OFFSET. CIE_OFFSET is the
|
2014-07-03 00:39:41 +08:00
|
|
|
// offset of the CIE in OVIEW. OUTPUT_OFFSET is the offset of the
|
|
|
|
// Eh_frame section within the output section. FDE_ENCODING is the
|
|
|
|
// encoding, from the CIE. ADDRALIGN is the required alignment.
|
|
|
|
// ADDRESS is the virtual address of OVIEW. Record the FDE pc for
|
|
|
|
// EH_FRAME_HDR. Return the new offset.
|
2007-11-09 15:00:15 +08:00
|
|
|
|
|
|
|
template<int size, bool big_endian>
|
2007-12-18 08:48:04 +08:00
|
|
|
section_offset_type
|
2014-07-03 00:39:41 +08:00
|
|
|
Fde::write(unsigned char* oview, section_offset_type output_offset,
|
|
|
|
section_offset_type offset, uint64_t address, unsigned int addralign,
|
PR gold/12571
* options.h (class General_options): Add
--ld-generated-unwind-info.
* ehframe.cc (Fde::write): Add address parameter. Change all
callers. If associated with PLT, fill in address and size.
(Cie::set_output_offset): Only add merge mapping if there is an
object.
(Cie::write): Add address parameter. Change all callers.
(Eh_frame::add_ehframe_for_plt): New function.
* ehframe.h (class Fde): Update declarations. Move shndx_ and
input_offset_ fields into union u_, with new plt field.
(Fde::Fde): Adjust for new union field.
(Fde::Fde) [Output_data version]: New constructor.
(Fde::add_mapping): Only add merge mapping if there is an object.
(class Cie): Update declarations.
(class Eh_frame): Declare add_ehframe_for_plt.
* layout.cc (Layout::layout_eh_frame): Break out code into
make_eh_frame_section, and call it.
(Layout::make_eh_frame_section): New function.
(Layout::add_eh_frame_for_plt): New function.
* layout.h (class Layout): Update declarations.
* merge.cc (Merge_map::add_mapping): Add assertion.
* i386.cc: Include "dwarf.h".
(class Output_data_plt_i386): Make first_plt_entry,
dyn_first_plt_entry, exec_plt_entry, and dyn_plt_entry const. Add
plt_eh_frame_cie_size, plt_eh_frame_fde_size, plt_eh_frame_cie,
and plt_eh_frame_fde.
(Output_data_plt_i386::Output_data_plt_i386): Align to 16-byte
boundary. Call add_eh_frame_for_plt if appropriate.
* x86_64.cc: Include "dwarf.h".
(class Output_data_plt_x86_64): Align to 16-byte boundary. Make
first_plt_entry, plt_entry and tlsdesc_plt_entry const. Add
plt_eh_frame_cie_size, plt_eh_frame_fde_size, plt_eh_frame_cie,
and plt_eh_frame_fde.
(Output_data_plt_x86_64::init): Call add_eh_frame_for_plt if
appropriate.
2011-07-02 06:05:01 +08:00
|
|
|
section_offset_type cie_offset, unsigned char fde_encoding,
|
|
|
|
Eh_frame_hdr* eh_frame_hdr)
|
2007-11-09 15:00:15 +08:00
|
|
|
{
|
2008-02-14 10:40:15 +08:00
|
|
|
gold_assert((offset & (addralign - 1)) == 0);
|
|
|
|
|
2009-12-15 03:53:05 +08:00
|
|
|
size_t length = this->contents_.length();
|
2007-11-09 15:00:15 +08:00
|
|
|
|
2008-02-14 10:40:15 +08:00
|
|
|
// We add 8 when getting the aligned length to account for the
|
|
|
|
// length word and the CIE offset.
|
2009-12-15 03:53:05 +08:00
|
|
|
size_t aligned_full_length = align_address(length + 8, addralign);
|
2008-02-14 10:40:15 +08:00
|
|
|
|
2007-11-09 15:00:15 +08:00
|
|
|
// Write the length of the FDE as a 32-bit word. The length word
|
|
|
|
// does not include the four bytes of the length word itself, but it
|
|
|
|
// does include the offset to the CIE.
|
|
|
|
elfcpp::Swap<32, big_endian>::writeval(oview + offset,
|
2008-02-14 10:40:15 +08:00
|
|
|
aligned_full_length - 4);
|
2007-11-09 15:00:15 +08:00
|
|
|
|
|
|
|
// Write the offset to the CIE as a 32-bit word. This is the
|
|
|
|
// difference between the address of the offset word itself and the
|
|
|
|
// CIE address.
|
|
|
|
elfcpp::Swap<32, big_endian>::writeval(oview + offset + 4,
|
|
|
|
offset + 4 - cie_offset);
|
|
|
|
|
|
|
|
// Copy the rest of the FDE. Note that this is run before
|
|
|
|
// relocation processing is done on this section, so the relocations
|
|
|
|
// will later be applied to the FDE data.
|
2009-12-15 03:53:05 +08:00
|
|
|
memcpy(oview + offset + 8, this->contents_.data(), length);
|
2007-11-09 15:00:15 +08:00
|
|
|
|
PR gold/12571
* options.h (class General_options): Add
--ld-generated-unwind-info.
* ehframe.cc (Fde::write): Add address parameter. Change all
callers. If associated with PLT, fill in address and size.
(Cie::set_output_offset): Only add merge mapping if there is an
object.
(Cie::write): Add address parameter. Change all callers.
(Eh_frame::add_ehframe_for_plt): New function.
* ehframe.h (class Fde): Update declarations. Move shndx_ and
input_offset_ fields into union u_, with new plt field.
(Fde::Fde): Adjust for new union field.
(Fde::Fde) [Output_data version]: New constructor.
(Fde::add_mapping): Only add merge mapping if there is an object.
(class Cie): Update declarations.
(class Eh_frame): Declare add_ehframe_for_plt.
* layout.cc (Layout::layout_eh_frame): Break out code into
make_eh_frame_section, and call it.
(Layout::make_eh_frame_section): New function.
(Layout::add_eh_frame_for_plt): New function.
* layout.h (class Layout): Update declarations.
* merge.cc (Merge_map::add_mapping): Add assertion.
* i386.cc: Include "dwarf.h".
(class Output_data_plt_i386): Make first_plt_entry,
dyn_first_plt_entry, exec_plt_entry, and dyn_plt_entry const. Add
plt_eh_frame_cie_size, plt_eh_frame_fde_size, plt_eh_frame_cie,
and plt_eh_frame_fde.
(Output_data_plt_i386::Output_data_plt_i386): Align to 16-byte
boundary. Call add_eh_frame_for_plt if appropriate.
* x86_64.cc: Include "dwarf.h".
(class Output_data_plt_x86_64): Align to 16-byte boundary. Make
first_plt_entry, plt_entry and tlsdesc_plt_entry const. Add
plt_eh_frame_cie_size, plt_eh_frame_fde_size, plt_eh_frame_cie,
and plt_eh_frame_fde.
(Output_data_plt_x86_64::init): Call add_eh_frame_for_plt if
appropriate.
2011-07-02 06:05:01 +08:00
|
|
|
// If this FDE is associated with a PLT, fill in the PLT's address
|
|
|
|
// and size.
|
|
|
|
if (this->object_ == NULL)
|
|
|
|
{
|
|
|
|
gold_assert(memcmp(oview + offset + 8, "\0\0\0\0\0\0\0\0", 8) == 0);
|
* target.h (Target::plt_fde_location, do_plt_fde_location): Declare.
* target.cc (Target::do_plt_fde_location): New function.
* ehframe.h (class FDE): Add post_map field to u_.from_linker,
accessor function, and constructor param.
(struct Post_fde, Post_fdes): Declare.
(Cie::write): Add post_fdes param.
* ehframe.cc (Fde::write): Use plt_fde_location.
(struct Post_fde): Define.
(Cie::write): Stash FDEs added post merge mapping.
(Eh_frame::add_ehframe_for_plt): Assert no new CIEs after mapping.
Adjust Fde constructor call. Bump final_data_size_ for post map FDEs.
(Eh_frame::do_sized_write): Arrange to write post map FDES after
other FDEs.
* powerpc.cc (Target_powerpc::do_plt_fde_location): New function.
(Target_powerpc::has_glink): New function.
(Target_powerpc::do_relax): Add eh_frame info for stubs.
(struct Eh_cie, eh_frame_cie, glink_eh_frame_fde_64,
glink_eh_frame_fde_32, default_fde): New data.
(Stub_table::eh_frame_added_): New var.
(Stub_table::find_long_branch_entry, stub_address, stub_offset):
Make const.
(Stub_table::add_eh_frame): New function.
(Output_data_glink::add_eh_frame): New function.
(Target_powerpc::make_glink_section): Call add_eh_frame.
2013-02-28 07:11:56 +08:00
|
|
|
uint64_t paddress;
|
|
|
|
off_t psize;
|
|
|
|
parameters->target().plt_fde_location(this->u_.from_linker.plt,
|
|
|
|
oview + offset + 8,
|
|
|
|
&paddress, &psize);
|
|
|
|
uint64_t poffset = paddress - (address + offset + 8);
|
PR gold/12571
* options.h (class General_options): Add
--ld-generated-unwind-info.
* ehframe.cc (Fde::write): Add address parameter. Change all
callers. If associated with PLT, fill in address and size.
(Cie::set_output_offset): Only add merge mapping if there is an
object.
(Cie::write): Add address parameter. Change all callers.
(Eh_frame::add_ehframe_for_plt): New function.
* ehframe.h (class Fde): Update declarations. Move shndx_ and
input_offset_ fields into union u_, with new plt field.
(Fde::Fde): Adjust for new union field.
(Fde::Fde) [Output_data version]: New constructor.
(Fde::add_mapping): Only add merge mapping if there is an object.
(class Cie): Update declarations.
(class Eh_frame): Declare add_ehframe_for_plt.
* layout.cc (Layout::layout_eh_frame): Break out code into
make_eh_frame_section, and call it.
(Layout::make_eh_frame_section): New function.
(Layout::add_eh_frame_for_plt): New function.
* layout.h (class Layout): Update declarations.
* merge.cc (Merge_map::add_mapping): Add assertion.
* i386.cc: Include "dwarf.h".
(class Output_data_plt_i386): Make first_plt_entry,
dyn_first_plt_entry, exec_plt_entry, and dyn_plt_entry const. Add
plt_eh_frame_cie_size, plt_eh_frame_fde_size, plt_eh_frame_cie,
and plt_eh_frame_fde.
(Output_data_plt_i386::Output_data_plt_i386): Align to 16-byte
boundary. Call add_eh_frame_for_plt if appropriate.
* x86_64.cc: Include "dwarf.h".
(class Output_data_plt_x86_64): Align to 16-byte boundary. Make
first_plt_entry, plt_entry and tlsdesc_plt_entry const. Add
plt_eh_frame_cie_size, plt_eh_frame_fde_size, plt_eh_frame_cie,
and plt_eh_frame_fde.
(Output_data_plt_x86_64::init): Call add_eh_frame_for_plt if
appropriate.
2011-07-02 06:05:01 +08:00
|
|
|
int32_t spoffset = static_cast<int32_t>(poffset);
|
|
|
|
uint32_t upsize = static_cast<uint32_t>(psize);
|
|
|
|
if (static_cast<uint64_t>(static_cast<int64_t>(spoffset)) != poffset
|
|
|
|
|| static_cast<off_t>(upsize) != psize)
|
|
|
|
gold_warning(_("overflow in PLT unwind data; "
|
|
|
|
"unwinding through PLT may fail"));
|
|
|
|
elfcpp::Swap<32, big_endian>::writeval(oview + offset + 8, spoffset);
|
|
|
|
elfcpp::Swap<32, big_endian>::writeval(oview + offset + 12, upsize);
|
|
|
|
}
|
|
|
|
|
2009-12-15 03:53:05 +08:00
|
|
|
if (aligned_full_length > length + 8)
|
|
|
|
memset(oview + offset + length + 8, 0, aligned_full_length - (length + 8));
|
2008-02-14 10:40:15 +08:00
|
|
|
|
2007-11-09 15:00:15 +08:00
|
|
|
// Tell the exception frame header about this FDE.
|
|
|
|
if (eh_frame_hdr != NULL)
|
2014-07-03 00:39:41 +08:00
|
|
|
eh_frame_hdr->record_fde(output_offset + offset, fde_encoding);
|
2007-11-09 15:00:15 +08:00
|
|
|
|
2008-02-14 10:40:15 +08:00
|
|
|
return offset + aligned_full_length;
|
2007-11-09 15:00:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Class Cie.
|
|
|
|
|
|
|
|
// Destructor.
|
|
|
|
|
|
|
|
Cie::~Cie()
|
|
|
|
{
|
|
|
|
for (std::vector<Fde*>::iterator p = this->fdes_.begin();
|
|
|
|
p != this->fdes_.end();
|
|
|
|
++p)
|
|
|
|
delete *p;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the output offset of a CIE. Return the new output offset.
|
|
|
|
|
2007-12-18 08:48:04 +08:00
|
|
|
section_offset_type
|
|
|
|
Cie::set_output_offset(section_offset_type output_offset,
|
|
|
|
unsigned int addralign,
|
2015-03-05 07:10:18 +08:00
|
|
|
Output_section_data *output_data)
|
2007-11-09 15:00:15 +08:00
|
|
|
{
|
|
|
|
size_t length = this->contents_.length();
|
2008-02-14 10:40:15 +08:00
|
|
|
|
2007-11-09 15:00:15 +08:00
|
|
|
// Add 4 for length and 4 for zero CIE identifier tag.
|
|
|
|
length += 8;
|
|
|
|
|
PR gold/12571
* options.h (class General_options): Add
--ld-generated-unwind-info.
* ehframe.cc (Fde::write): Add address parameter. Change all
callers. If associated with PLT, fill in address and size.
(Cie::set_output_offset): Only add merge mapping if there is an
object.
(Cie::write): Add address parameter. Change all callers.
(Eh_frame::add_ehframe_for_plt): New function.
* ehframe.h (class Fde): Update declarations. Move shndx_ and
input_offset_ fields into union u_, with new plt field.
(Fde::Fde): Adjust for new union field.
(Fde::Fde) [Output_data version]: New constructor.
(Fde::add_mapping): Only add merge mapping if there is an object.
(class Cie): Update declarations.
(class Eh_frame): Declare add_ehframe_for_plt.
* layout.cc (Layout::layout_eh_frame): Break out code into
make_eh_frame_section, and call it.
(Layout::make_eh_frame_section): New function.
(Layout::add_eh_frame_for_plt): New function.
* layout.h (class Layout): Update declarations.
* merge.cc (Merge_map::add_mapping): Add assertion.
* i386.cc: Include "dwarf.h".
(class Output_data_plt_i386): Make first_plt_entry,
dyn_first_plt_entry, exec_plt_entry, and dyn_plt_entry const. Add
plt_eh_frame_cie_size, plt_eh_frame_fde_size, plt_eh_frame_cie,
and plt_eh_frame_fde.
(Output_data_plt_i386::Output_data_plt_i386): Align to 16-byte
boundary. Call add_eh_frame_for_plt if appropriate.
* x86_64.cc: Include "dwarf.h".
(class Output_data_plt_x86_64): Align to 16-byte boundary. Make
first_plt_entry, plt_entry and tlsdesc_plt_entry const. Add
plt_eh_frame_cie_size, plt_eh_frame_fde_size, plt_eh_frame_cie,
and plt_eh_frame_fde.
(Output_data_plt_x86_64::init): Call add_eh_frame_for_plt if
appropriate.
2011-07-02 06:05:01 +08:00
|
|
|
if (this->object_ != NULL)
|
|
|
|
{
|
|
|
|
// Add a mapping so that relocations are applied correctly.
|
2015-03-05 07:10:18 +08:00
|
|
|
this->object_->add_merge_mapping(output_data, this->shndx_,
|
|
|
|
this->input_offset_, length,
|
|
|
|
output_offset);
|
PR gold/12571
* options.h (class General_options): Add
--ld-generated-unwind-info.
* ehframe.cc (Fde::write): Add address parameter. Change all
callers. If associated with PLT, fill in address and size.
(Cie::set_output_offset): Only add merge mapping if there is an
object.
(Cie::write): Add address parameter. Change all callers.
(Eh_frame::add_ehframe_for_plt): New function.
* ehframe.h (class Fde): Update declarations. Move shndx_ and
input_offset_ fields into union u_, with new plt field.
(Fde::Fde): Adjust for new union field.
(Fde::Fde) [Output_data version]: New constructor.
(Fde::add_mapping): Only add merge mapping if there is an object.
(class Cie): Update declarations.
(class Eh_frame): Declare add_ehframe_for_plt.
* layout.cc (Layout::layout_eh_frame): Break out code into
make_eh_frame_section, and call it.
(Layout::make_eh_frame_section): New function.
(Layout::add_eh_frame_for_plt): New function.
* layout.h (class Layout): Update declarations.
* merge.cc (Merge_map::add_mapping): Add assertion.
* i386.cc: Include "dwarf.h".
(class Output_data_plt_i386): Make first_plt_entry,
dyn_first_plt_entry, exec_plt_entry, and dyn_plt_entry const. Add
plt_eh_frame_cie_size, plt_eh_frame_fde_size, plt_eh_frame_cie,
and plt_eh_frame_fde.
(Output_data_plt_i386::Output_data_plt_i386): Align to 16-byte
boundary. Call add_eh_frame_for_plt if appropriate.
* x86_64.cc: Include "dwarf.h".
(class Output_data_plt_x86_64): Align to 16-byte boundary. Make
first_plt_entry, plt_entry and tlsdesc_plt_entry const. Add
plt_eh_frame_cie_size, plt_eh_frame_fde_size, plt_eh_frame_cie,
and plt_eh_frame_fde.
(Output_data_plt_x86_64::init): Call add_eh_frame_for_plt if
appropriate.
2011-07-02 06:05:01 +08:00
|
|
|
}
|
2007-11-09 15:00:15 +08:00
|
|
|
|
2008-02-14 10:40:15 +08:00
|
|
|
length = align_address(length, addralign);
|
|
|
|
|
2007-11-09 15:00:15 +08:00
|
|
|
for (std::vector<Fde*>::const_iterator p = this->fdes_.begin();
|
|
|
|
p != this->fdes_.end();
|
|
|
|
++p)
|
|
|
|
{
|
2015-03-05 07:10:18 +08:00
|
|
|
(*p)->add_mapping(output_offset + length, output_data);
|
2007-11-09 15:00:15 +08:00
|
|
|
|
|
|
|
size_t fde_length = (*p)->length();
|
2008-02-14 10:40:15 +08:00
|
|
|
fde_length = align_address(fde_length, addralign);
|
2007-11-09 15:00:15 +08:00
|
|
|
length += fde_length;
|
|
|
|
}
|
|
|
|
|
|
|
|
return output_offset + length;
|
|
|
|
}
|
|
|
|
|
2014-07-03 00:39:41 +08:00
|
|
|
// Write the CIE to OVIEW starting at OFFSET. OUTPUT_OFFSET is the
|
|
|
|
// offset of the Eh_frame section within the output section. Round up
|
|
|
|
// the bytes to ADDRALIGN. ADDRESS is the virtual address of OVIEW.
|
* target.h (Target::plt_fde_location, do_plt_fde_location): Declare.
* target.cc (Target::do_plt_fde_location): New function.
* ehframe.h (class FDE): Add post_map field to u_.from_linker,
accessor function, and constructor param.
(struct Post_fde, Post_fdes): Declare.
(Cie::write): Add post_fdes param.
* ehframe.cc (Fde::write): Use plt_fde_location.
(struct Post_fde): Define.
(Cie::write): Stash FDEs added post merge mapping.
(Eh_frame::add_ehframe_for_plt): Assert no new CIEs after mapping.
Adjust Fde constructor call. Bump final_data_size_ for post map FDEs.
(Eh_frame::do_sized_write): Arrange to write post map FDES after
other FDEs.
* powerpc.cc (Target_powerpc::do_plt_fde_location): New function.
(Target_powerpc::has_glink): New function.
(Target_powerpc::do_relax): Add eh_frame info for stubs.
(struct Eh_cie, eh_frame_cie, glink_eh_frame_fde_64,
glink_eh_frame_fde_32, default_fde): New data.
(Stub_table::eh_frame_added_): New var.
(Stub_table::find_long_branch_entry, stub_address, stub_offset):
Make const.
(Stub_table::add_eh_frame): New function.
(Output_data_glink::add_eh_frame): New function.
(Target_powerpc::make_glink_section): Call add_eh_frame.
2013-02-28 07:11:56 +08:00
|
|
|
// EH_FRAME_HDR is the exception frame header for FDE recording.
|
|
|
|
// POST_FDES stashes FDEs created after mappings were done, for later
|
|
|
|
// writing. Return the new offset.
|
2007-11-09 15:00:15 +08:00
|
|
|
|
|
|
|
template<int size, bool big_endian>
|
2007-12-18 08:48:04 +08:00
|
|
|
section_offset_type
|
2014-07-03 00:39:41 +08:00
|
|
|
Cie::write(unsigned char* oview, section_offset_type output_offset,
|
|
|
|
section_offset_type offset, uint64_t address,
|
|
|
|
unsigned int addralign, Eh_frame_hdr* eh_frame_hdr,
|
|
|
|
Post_fdes* post_fdes)
|
2007-11-09 15:00:15 +08:00
|
|
|
{
|
2008-02-14 10:40:15 +08:00
|
|
|
gold_assert((offset & (addralign - 1)) == 0);
|
|
|
|
|
2007-12-18 08:48:04 +08:00
|
|
|
section_offset_type cie_offset = offset;
|
2007-11-09 15:00:15 +08:00
|
|
|
|
|
|
|
size_t length = this->contents_.length();
|
|
|
|
|
2008-02-14 10:40:15 +08:00
|
|
|
// We add 8 when getting the aligned length to account for the
|
|
|
|
// length word and the CIE tag.
|
|
|
|
size_t aligned_full_length = align_address(length + 8, addralign);
|
|
|
|
|
2007-11-09 15:00:15 +08:00
|
|
|
// Write the length of the CIE as a 32-bit word. The length word
|
|
|
|
// does not include the four bytes of the length word itself.
|
2008-02-14 10:40:15 +08:00
|
|
|
elfcpp::Swap<32, big_endian>::writeval(oview + offset,
|
|
|
|
aligned_full_length - 4);
|
2007-11-09 15:00:15 +08:00
|
|
|
|
|
|
|
// Write the tag which marks this as a CIE: a 32-bit zero.
|
|
|
|
elfcpp::Swap<32, big_endian>::writeval(oview + offset + 4, 0);
|
|
|
|
|
|
|
|
// Write out the CIE data.
|
|
|
|
memcpy(oview + offset + 8, this->contents_.data(), length);
|
2008-02-14 10:40:15 +08:00
|
|
|
|
|
|
|
if (aligned_full_length > length + 8)
|
|
|
|
memset(oview + offset + length + 8, 0, aligned_full_length - (length + 8));
|
|
|
|
|
|
|
|
offset += aligned_full_length;
|
2007-11-09 15:00:15 +08:00
|
|
|
|
|
|
|
// Write out the associated FDEs.
|
|
|
|
unsigned char fde_encoding = this->fde_encoding_;
|
|
|
|
for (std::vector<Fde*>::const_iterator p = this->fdes_.begin();
|
|
|
|
p != this->fdes_.end();
|
|
|
|
++p)
|
* target.h (Target::plt_fde_location, do_plt_fde_location): Declare.
* target.cc (Target::do_plt_fde_location): New function.
* ehframe.h (class FDE): Add post_map field to u_.from_linker,
accessor function, and constructor param.
(struct Post_fde, Post_fdes): Declare.
(Cie::write): Add post_fdes param.
* ehframe.cc (Fde::write): Use plt_fde_location.
(struct Post_fde): Define.
(Cie::write): Stash FDEs added post merge mapping.
(Eh_frame::add_ehframe_for_plt): Assert no new CIEs after mapping.
Adjust Fde constructor call. Bump final_data_size_ for post map FDEs.
(Eh_frame::do_sized_write): Arrange to write post map FDES after
other FDEs.
* powerpc.cc (Target_powerpc::do_plt_fde_location): New function.
(Target_powerpc::has_glink): New function.
(Target_powerpc::do_relax): Add eh_frame info for stubs.
(struct Eh_cie, eh_frame_cie, glink_eh_frame_fde_64,
glink_eh_frame_fde_32, default_fde): New data.
(Stub_table::eh_frame_added_): New var.
(Stub_table::find_long_branch_entry, stub_address, stub_offset):
Make const.
(Stub_table::add_eh_frame): New function.
(Output_data_glink::add_eh_frame): New function.
(Target_powerpc::make_glink_section): Call add_eh_frame.
2013-02-28 07:11:56 +08:00
|
|
|
{
|
|
|
|
if ((*p)->post_map())
|
2013-03-08 07:27:53 +08:00
|
|
|
post_fdes->push_back(Post_fde(*p, cie_offset, fde_encoding));
|
* target.h (Target::plt_fde_location, do_plt_fde_location): Declare.
* target.cc (Target::do_plt_fde_location): New function.
* ehframe.h (class FDE): Add post_map field to u_.from_linker,
accessor function, and constructor param.
(struct Post_fde, Post_fdes): Declare.
(Cie::write): Add post_fdes param.
* ehframe.cc (Fde::write): Use plt_fde_location.
(struct Post_fde): Define.
(Cie::write): Stash FDEs added post merge mapping.
(Eh_frame::add_ehframe_for_plt): Assert no new CIEs after mapping.
Adjust Fde constructor call. Bump final_data_size_ for post map FDEs.
(Eh_frame::do_sized_write): Arrange to write post map FDES after
other FDEs.
* powerpc.cc (Target_powerpc::do_plt_fde_location): New function.
(Target_powerpc::has_glink): New function.
(Target_powerpc::do_relax): Add eh_frame info for stubs.
(struct Eh_cie, eh_frame_cie, glink_eh_frame_fde_64,
glink_eh_frame_fde_32, default_fde): New data.
(Stub_table::eh_frame_added_): New var.
(Stub_table::find_long_branch_entry, stub_address, stub_offset):
Make const.
(Stub_table::add_eh_frame): New function.
(Output_data_glink::add_eh_frame): New function.
(Target_powerpc::make_glink_section): Call add_eh_frame.
2013-02-28 07:11:56 +08:00
|
|
|
else
|
2014-07-03 00:39:41 +08:00
|
|
|
offset = (*p)->write<size, big_endian>(oview, output_offset, offset,
|
|
|
|
address, addralign, cie_offset,
|
* target.h (Target::plt_fde_location, do_plt_fde_location): Declare.
* target.cc (Target::do_plt_fde_location): New function.
* ehframe.h (class FDE): Add post_map field to u_.from_linker,
accessor function, and constructor param.
(struct Post_fde, Post_fdes): Declare.
(Cie::write): Add post_fdes param.
* ehframe.cc (Fde::write): Use plt_fde_location.
(struct Post_fde): Define.
(Cie::write): Stash FDEs added post merge mapping.
(Eh_frame::add_ehframe_for_plt): Assert no new CIEs after mapping.
Adjust Fde constructor call. Bump final_data_size_ for post map FDEs.
(Eh_frame::do_sized_write): Arrange to write post map FDES after
other FDEs.
* powerpc.cc (Target_powerpc::do_plt_fde_location): New function.
(Target_powerpc::has_glink): New function.
(Target_powerpc::do_relax): Add eh_frame info for stubs.
(struct Eh_cie, eh_frame_cie, glink_eh_frame_fde_64,
glink_eh_frame_fde_32, default_fde): New data.
(Stub_table::eh_frame_added_): New var.
(Stub_table::find_long_branch_entry, stub_address, stub_offset):
Make const.
(Stub_table::add_eh_frame): New function.
(Output_data_glink::add_eh_frame): New function.
(Target_powerpc::make_glink_section): Call add_eh_frame.
2013-02-28 07:11:56 +08:00
|
|
|
fde_encoding, eh_frame_hdr);
|
|
|
|
}
|
2007-11-09 15:00:15 +08:00
|
|
|
|
|
|
|
return offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We track all the CIEs we see, and merge them when possible. This
|
|
|
|
// works because each FDE holds an offset to the relevant CIE: we
|
|
|
|
// rewrite the FDEs to point to the merged CIE. This is worthwhile
|
|
|
|
// because in a typical C++ program many FDEs in many different object
|
|
|
|
// files will use the same CIE.
|
|
|
|
|
|
|
|
// An equality operator for Cie.
|
|
|
|
|
|
|
|
bool
|
|
|
|
operator==(const Cie& cie1, const Cie& cie2)
|
|
|
|
{
|
|
|
|
return (cie1.personality_name_ == cie2.personality_name_
|
|
|
|
&& cie1.contents_ == cie2.contents_);
|
|
|
|
}
|
|
|
|
|
|
|
|
// A less-than operator for Cie.
|
|
|
|
|
|
|
|
bool
|
|
|
|
operator<(const Cie& cie1, const Cie& cie2)
|
|
|
|
{
|
|
|
|
if (cie1.personality_name_ != cie2.personality_name_)
|
|
|
|
return cie1.personality_name_ < cie2.personality_name_;
|
|
|
|
return cie1.contents_ < cie2.contents_;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Class Eh_frame.
|
|
|
|
|
|
|
|
Eh_frame::Eh_frame()
|
|
|
|
: Output_section_data(Output_data::default_alignment()),
|
|
|
|
eh_frame_hdr_(NULL),
|
|
|
|
cie_offsets_(),
|
|
|
|
unmergeable_cie_offsets_(),
|
2008-03-14 04:58:11 +08:00
|
|
|
mappings_are_done_(false),
|
|
|
|
final_data_size_(0)
|
2007-11-09 15:00:15 +08:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
// Skip an LEB128, updating *PP to point to the next character.
|
|
|
|
// Return false if we ran off the end of the string.
|
|
|
|
|
|
|
|
bool
|
|
|
|
Eh_frame::skip_leb128(const unsigned char** pp, const unsigned char* pend)
|
|
|
|
{
|
|
|
|
const unsigned char* p;
|
|
|
|
for (p = *pp; p < pend; ++p)
|
|
|
|
{
|
|
|
|
if ((*p & 0x80) == 0)
|
|
|
|
{
|
|
|
|
*pp = p + 1;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add input section SHNDX in OBJECT to an exception frame section.
|
|
|
|
// SYMBOLS is the contents of the symbol table section (size
|
|
|
|
// SYMBOLS_SIZE), SYMBOL_NAMES is the symbol names section (size
|
|
|
|
// SYMBOL_NAMES_SIZE). RELOC_SHNDX is the index of a relocation
|
|
|
|
// section applying to SHNDX, or 0 if none, or -1U if more than one.
|
|
|
|
// RELOC_TYPE is the type of the reloc section if there is one, either
|
|
|
|
// SHT_REL or SHT_RELA. We try to parse the input exception frame
|
|
|
|
// data into our data structures. If we can't do it, we return false
|
|
|
|
// to mean that the section should be handled as a normal input
|
|
|
|
// section.
|
|
|
|
|
|
|
|
template<int size, bool big_endian>
|
2015-03-10 01:10:29 +08:00
|
|
|
Eh_frame::Eh_frame_section_disposition
|
2007-11-09 15:00:15 +08:00
|
|
|
Eh_frame::add_ehframe_input_section(
|
2011-05-25 05:41:10 +08:00
|
|
|
Sized_relobj_file<size, big_endian>* object,
|
2007-11-09 15:00:15 +08:00
|
|
|
const unsigned char* symbols,
|
2007-12-18 08:48:04 +08:00
|
|
|
section_size_type symbols_size,
|
2007-11-09 15:00:15 +08:00
|
|
|
const unsigned char* symbol_names,
|
2007-12-18 08:48:04 +08:00
|
|
|
section_size_type symbol_names_size,
|
2007-11-09 15:00:15 +08:00
|
|
|
unsigned int shndx,
|
|
|
|
unsigned int reloc_shndx,
|
|
|
|
unsigned int reloc_type)
|
|
|
|
{
|
|
|
|
// Get the section contents.
|
2007-12-18 08:48:04 +08:00
|
|
|
section_size_type contents_len;
|
2007-11-09 15:00:15 +08:00
|
|
|
const unsigned char* pcontents = object->section_contents(shndx,
|
|
|
|
&contents_len,
|
|
|
|
false);
|
|
|
|
if (contents_len == 0)
|
2015-03-10 01:10:29 +08:00
|
|
|
return EH_EMPTY_SECTION;
|
2007-11-09 15:00:15 +08:00
|
|
|
|
|
|
|
// If this is the marker section for the end of the data, then
|
|
|
|
// return false to force it to be handled as an ordinary input
|
|
|
|
// section. If we don't do this, we won't correctly handle the case
|
|
|
|
// of unrecognized .eh_frame sections.
|
|
|
|
if (contents_len == 4
|
|
|
|
&& elfcpp::Swap<32, big_endian>::readval(pcontents) == 0)
|
2015-03-10 01:10:29 +08:00
|
|
|
return EH_END_MARKER_SECTION;
|
2007-11-09 15:00:15 +08:00
|
|
|
|
|
|
|
New_cies new_cies;
|
|
|
|
if (!this->do_add_ehframe_input_section(object, symbols, symbols_size,
|
|
|
|
symbol_names, symbol_names_size,
|
|
|
|
shndx, reloc_shndx,
|
|
|
|
reloc_type, pcontents,
|
|
|
|
contents_len, &new_cies))
|
|
|
|
{
|
2008-07-25 05:23:09 +08:00
|
|
|
if (this->eh_frame_hdr_ != NULL)
|
|
|
|
this->eh_frame_hdr_->found_unrecognized_eh_frame_section();
|
2007-11-09 15:00:15 +08:00
|
|
|
|
|
|
|
for (New_cies::iterator p = new_cies.begin();
|
|
|
|
p != new_cies.end();
|
|
|
|
++p)
|
|
|
|
delete p->first;
|
|
|
|
|
2015-03-10 01:10:29 +08:00
|
|
|
return EH_UNRECOGNIZED_SECTION;
|
2007-11-09 15:00:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Now that we know we are using this section, record any new CIEs
|
|
|
|
// that we found.
|
|
|
|
for (New_cies::const_iterator p = new_cies.begin();
|
|
|
|
p != new_cies.end();
|
|
|
|
++p)
|
|
|
|
{
|
|
|
|
if (p->second)
|
2008-02-02 14:50:45 +08:00
|
|
|
this->cie_offsets_.insert(p->first);
|
2007-11-09 15:00:15 +08:00
|
|
|
else
|
2008-02-02 14:50:45 +08:00
|
|
|
this->unmergeable_cie_offsets_.push_back(p->first);
|
2007-11-09 15:00:15 +08:00
|
|
|
}
|
|
|
|
|
2015-03-10 01:10:29 +08:00
|
|
|
return EH_OPTIMIZABLE_SECTION;
|
2007-11-09 15:00:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// The bulk of the implementation of add_ehframe_input_section.
|
|
|
|
|
|
|
|
template<int size, bool big_endian>
|
|
|
|
bool
|
|
|
|
Eh_frame::do_add_ehframe_input_section(
|
2011-05-25 05:41:10 +08:00
|
|
|
Sized_relobj_file<size, big_endian>* object,
|
2007-11-09 15:00:15 +08:00
|
|
|
const unsigned char* symbols,
|
2007-12-18 08:48:04 +08:00
|
|
|
section_size_type symbols_size,
|
2007-11-09 15:00:15 +08:00
|
|
|
const unsigned char* symbol_names,
|
2007-12-18 08:48:04 +08:00
|
|
|
section_size_type symbol_names_size,
|
2007-11-09 15:00:15 +08:00
|
|
|
unsigned int shndx,
|
|
|
|
unsigned int reloc_shndx,
|
|
|
|
unsigned int reloc_type,
|
|
|
|
const unsigned char* pcontents,
|
2007-12-18 08:48:04 +08:00
|
|
|
section_size_type contents_len,
|
2007-11-09 15:00:15 +08:00
|
|
|
New_cies* new_cies)
|
|
|
|
{
|
|
|
|
Track_relocs<size, big_endian> relocs;
|
|
|
|
|
|
|
|
const unsigned char* p = pcontents;
|
|
|
|
const unsigned char* pend = p + contents_len;
|
|
|
|
|
|
|
|
// Get the contents of the reloc section if any.
|
|
|
|
if (!relocs.initialize(object, reloc_shndx, reloc_type))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Keep track of which CIEs are at which offsets.
|
|
|
|
Offsets_to_cie cies;
|
|
|
|
|
|
|
|
while (p < pend)
|
|
|
|
{
|
|
|
|
if (pend - p < 4)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// There shouldn't be any relocations here.
|
|
|
|
if (relocs.advance(p + 4 - pcontents) > 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
unsigned int len = elfcpp::Swap<32, big_endian>::readval(p);
|
|
|
|
p += 4;
|
|
|
|
if (len == 0)
|
|
|
|
{
|
|
|
|
// We should only find a zero-length entry at the end of the
|
|
|
|
// section.
|
|
|
|
if (p < pend)
|
|
|
|
return false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// We don't support a 64-bit .eh_frame.
|
|
|
|
if (len == 0xffffffff)
|
|
|
|
return false;
|
|
|
|
if (static_cast<unsigned int>(pend - p) < len)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const unsigned char* const pentend = p + len;
|
|
|
|
|
|
|
|
if (pend - p < 4)
|
|
|
|
return false;
|
|
|
|
if (relocs.advance(p + 4 - pcontents) > 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
unsigned int id = elfcpp::Swap<32, big_endian>::readval(p);
|
|
|
|
p += 4;
|
|
|
|
|
|
|
|
if (id == 0)
|
|
|
|
{
|
|
|
|
// CIE.
|
|
|
|
if (!this->read_cie(object, shndx, symbols, symbols_size,
|
|
|
|
symbol_names, symbol_names_size,
|
|
|
|
pcontents, p, pentend, &relocs, &cies,
|
|
|
|
new_cies))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// FDE.
|
|
|
|
if (!this->read_fde(object, shndx, symbols, symbols_size,
|
|
|
|
pcontents, id, p, pentend, &relocs, &cies))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
p = pentend;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read a CIE. Return false if we can't parse the information.
|
|
|
|
|
|
|
|
template<int size, bool big_endian>
|
|
|
|
bool
|
2011-05-25 05:41:10 +08:00
|
|
|
Eh_frame::read_cie(Sized_relobj_file<size, big_endian>* object,
|
2007-11-09 15:00:15 +08:00
|
|
|
unsigned int shndx,
|
|
|
|
const unsigned char* symbols,
|
2007-12-18 08:48:04 +08:00
|
|
|
section_size_type symbols_size,
|
2007-11-09 15:00:15 +08:00
|
|
|
const unsigned char* symbol_names,
|
2007-12-18 08:48:04 +08:00
|
|
|
section_size_type symbol_names_size,
|
2007-11-09 15:00:15 +08:00
|
|
|
const unsigned char* pcontents,
|
|
|
|
const unsigned char* pcie,
|
2010-08-25 16:36:54 +08:00
|
|
|
const unsigned char* pcieend,
|
2007-11-09 15:00:15 +08:00
|
|
|
Track_relocs<size, big_endian>* relocs,
|
|
|
|
Offsets_to_cie* cies,
|
|
|
|
New_cies* new_cies)
|
|
|
|
{
|
|
|
|
bool mergeable = true;
|
|
|
|
|
|
|
|
// We need to find the personality routine if there is one, since we
|
|
|
|
// can only merge CIEs which use the same routine. We also need to
|
|
|
|
// find the FDE encoding if there is one, so that we can read the PC
|
|
|
|
// from the FDE.
|
|
|
|
|
|
|
|
const unsigned char* p = pcie;
|
|
|
|
|
|
|
|
if (pcieend - p < 1)
|
|
|
|
return false;
|
|
|
|
unsigned char version = *p++;
|
|
|
|
if (version != 1 && version != 3)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const unsigned char* paug = p;
|
|
|
|
const void* paugendv = memchr(p, '\0', pcieend - p);
|
|
|
|
const unsigned char* paugend = static_cast<const unsigned char*>(paugendv);
|
|
|
|
if (paugend == NULL)
|
|
|
|
return false;
|
|
|
|
p = paugend + 1;
|
|
|
|
|
|
|
|
if (paug[0] == 'e' && paug[1] == 'h')
|
|
|
|
{
|
|
|
|
// This is a CIE from gcc before version 3.0. We can't merge
|
|
|
|
// these. We can still read the FDEs.
|
|
|
|
mergeable = false;
|
|
|
|
paug += 2;
|
|
|
|
if (*paug != '\0')
|
|
|
|
return false;
|
|
|
|
if (pcieend - p < size / 8)
|
|
|
|
return false;
|
|
|
|
p += size / 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Skip the code alignment.
|
|
|
|
if (!skip_leb128(&p, pcieend))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Skip the data alignment.
|
|
|
|
if (!skip_leb128(&p, pcieend))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Skip the return column.
|
|
|
|
if (version == 1)
|
|
|
|
{
|
|
|
|
if (pcieend - p < 1)
|
|
|
|
return false;
|
|
|
|
++p;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!skip_leb128(&p, pcieend))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*paug == 'z')
|
|
|
|
{
|
|
|
|
++paug;
|
|
|
|
// Skip the augmentation size.
|
|
|
|
if (!skip_leb128(&p, pcieend))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char fde_encoding = elfcpp::DW_EH_PE_absptr;
|
|
|
|
int per_offset = -1;
|
|
|
|
while (*paug != '\0')
|
|
|
|
{
|
|
|
|
switch (*paug)
|
|
|
|
{
|
|
|
|
case 'L': // LSDA encoding.
|
|
|
|
if (pcieend - p < 1)
|
|
|
|
return false;
|
|
|
|
++p;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'R': // FDE encoding.
|
|
|
|
if (pcieend - p < 1)
|
|
|
|
return false;
|
|
|
|
fde_encoding = *p;
|
|
|
|
switch (fde_encoding & 7)
|
|
|
|
{
|
|
|
|
case elfcpp::DW_EH_PE_absptr:
|
|
|
|
case elfcpp::DW_EH_PE_udata2:
|
|
|
|
case elfcpp::DW_EH_PE_udata4:
|
|
|
|
case elfcpp::DW_EH_PE_udata8:
|
|
|
|
break;
|
|
|
|
default:
|
2007-12-07 14:44:01 +08:00
|
|
|
// We don't expect to see any other cases here, and
|
|
|
|
// we're not prepared to handle them.
|
2007-11-09 15:00:15 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
++p;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'S':
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'P':
|
|
|
|
// Personality encoding.
|
|
|
|
{
|
|
|
|
if (pcieend - p < 1)
|
|
|
|
return false;
|
|
|
|
unsigned char per_encoding = *p;
|
|
|
|
++p;
|
|
|
|
|
|
|
|
if ((per_encoding & 0x60) == 0x60)
|
|
|
|
return false;
|
|
|
|
unsigned int per_width;
|
|
|
|
switch (per_encoding & 7)
|
|
|
|
{
|
|
|
|
case elfcpp::DW_EH_PE_udata2:
|
|
|
|
per_width = 2;
|
|
|
|
break;
|
|
|
|
case elfcpp::DW_EH_PE_udata4:
|
|
|
|
per_width = 4;
|
|
|
|
break;
|
|
|
|
case elfcpp::DW_EH_PE_udata8:
|
|
|
|
per_width = 8;
|
|
|
|
break;
|
|
|
|
case elfcpp::DW_EH_PE_absptr:
|
|
|
|
per_width = size / 8;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((per_encoding & 0xf0) == elfcpp::DW_EH_PE_aligned)
|
|
|
|
{
|
|
|
|
unsigned int len = p - pcie;
|
|
|
|
len += per_width - 1;
|
|
|
|
len &= ~ (per_width - 1);
|
|
|
|
if (static_cast<unsigned int>(pcieend - p) < len)
|
|
|
|
return false;
|
|
|
|
p += len;
|
|
|
|
}
|
|
|
|
|
|
|
|
per_offset = p - pcontents;
|
|
|
|
|
|
|
|
if (static_cast<unsigned int>(pcieend - p) < per_width)
|
|
|
|
return false;
|
|
|
|
p += per_width;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
++paug;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* personality_name = "";
|
|
|
|
if (per_offset != -1)
|
|
|
|
{
|
|
|
|
if (relocs->advance(per_offset) > 0)
|
|
|
|
return false;
|
|
|
|
if (relocs->next_offset() != per_offset)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
unsigned int personality_symndx = relocs->next_symndx();
|
|
|
|
if (personality_symndx == -1U)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (personality_symndx < object->local_symbol_count())
|
|
|
|
{
|
|
|
|
// We can only merge this CIE if the personality routine is
|
|
|
|
// a global symbol. We can still read the FDEs.
|
|
|
|
mergeable = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
|
|
|
|
if (personality_symndx >= symbols_size / sym_size)
|
|
|
|
return false;
|
|
|
|
elfcpp::Sym<size, big_endian> sym(symbols
|
|
|
|
+ (personality_symndx * sym_size));
|
|
|
|
unsigned int name_offset = sym.get_st_name();
|
|
|
|
if (name_offset >= symbol_names_size)
|
|
|
|
return false;
|
|
|
|
personality_name = (reinterpret_cast<const char*>(symbol_names)
|
|
|
|
+ name_offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
int r = relocs->advance(per_offset + 1);
|
|
|
|
gold_assert(r == 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (relocs->advance(pcieend - pcontents) > 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
Cie cie(object, shndx, (pcie - 8) - pcontents, fde_encoding,
|
|
|
|
personality_name, pcie, pcieend - pcie);
|
|
|
|
Cie* cie_pointer = NULL;
|
|
|
|
if (mergeable)
|
|
|
|
{
|
|
|
|
Cie_offsets::iterator find_cie = this->cie_offsets_.find(&cie);
|
|
|
|
if (find_cie != this->cie_offsets_.end())
|
2008-02-02 14:50:45 +08:00
|
|
|
cie_pointer = *find_cie;
|
2007-11-09 15:00:15 +08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// See if we already saw this CIE in this object file.
|
|
|
|
for (New_cies::const_iterator pc = new_cies->begin();
|
|
|
|
pc != new_cies->end();
|
|
|
|
++pc)
|
|
|
|
{
|
|
|
|
if (*(pc->first) == cie)
|
|
|
|
{
|
|
|
|
cie_pointer = pc->first;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cie_pointer == NULL)
|
|
|
|
{
|
|
|
|
cie_pointer = new Cie(cie);
|
|
|
|
new_cies->push_back(std::make_pair(cie_pointer, mergeable));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// We are deleting this CIE. Record that in our mapping from
|
|
|
|
// input sections to the output section. At this point we don't
|
|
|
|
// know for sure that we are doing a special mapping for this
|
|
|
|
// input section, but that's OK--if we don't do a special
|
|
|
|
// mapping, nobody will ever ask for the mapping we add here.
|
2015-03-05 07:10:18 +08:00
|
|
|
object->add_merge_mapping(this, shndx, (pcie - 8) - pcontents,
|
|
|
|
pcieend - (pcie - 8), -1);
|
2007-11-09 15:00:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Record this CIE plus the offset in the input section.
|
|
|
|
cies->insert(std::make_pair(pcie - pcontents, cie_pointer));
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read an FDE. Return false if we can't parse the information.
|
|
|
|
|
|
|
|
template<int size, bool big_endian>
|
|
|
|
bool
|
2011-05-25 05:41:10 +08:00
|
|
|
Eh_frame::read_fde(Sized_relobj_file<size, big_endian>* object,
|
2007-11-09 15:00:15 +08:00
|
|
|
unsigned int shndx,
|
|
|
|
const unsigned char* symbols,
|
2007-12-18 08:48:04 +08:00
|
|
|
section_size_type symbols_size,
|
2007-11-09 15:00:15 +08:00
|
|
|
const unsigned char* pcontents,
|
2009-12-15 03:53:05 +08:00
|
|
|
unsigned int offset,
|
2007-11-09 15:00:15 +08:00
|
|
|
const unsigned char* pfde,
|
2010-08-25 16:36:54 +08:00
|
|
|
const unsigned char* pfdeend,
|
2007-11-09 15:00:15 +08:00
|
|
|
Track_relocs<size, big_endian>* relocs,
|
|
|
|
Offsets_to_cie* cies)
|
|
|
|
{
|
2009-12-15 03:53:05 +08:00
|
|
|
// OFFSET is the distance between the 4 bytes before PFDE to the
|
2007-11-09 15:00:15 +08:00
|
|
|
// start of the CIE. The offset we recorded for the CIE is 8 bytes
|
|
|
|
// after the start of the CIE--after the length and the zero tag.
|
2009-12-15 03:53:05 +08:00
|
|
|
unsigned int cie_offset = (pfde - 4 - pcontents) - offset + 8;
|
2007-11-09 15:00:15 +08:00
|
|
|
Offsets_to_cie::const_iterator pcie = cies->find(cie_offset);
|
|
|
|
if (pcie == cies->end())
|
|
|
|
return false;
|
|
|
|
Cie* cie = pcie->second;
|
|
|
|
|
Fix problem where gold cannot build .eh_frame_hdr from ld -r output.
When running ld -r on objects that have comdat groups, when gold
deduplicates a function in a comdat group, it removes the relocations
from the EH information that referred to the dropped copy of the function.
When running a final link using the result of the -r link, the missing
relocation cause it to fail to recognize the FDE for the dropped
function.
This patch improves gold's FDE scanning to take into account the
possibility that an FDE corresponds to a dropped function, and drops
that FDE as well.
Gnu ld, on the other hand, leaves the relocations in the ld -r output,
but makes them R_NONE with an r_sym field of 0. This was sufficient to
let both linkers recognize the FDE properly.
With this fix, if you do an ld -r with gold, then do the final link with
Gnu ld, the .eh_frame_hdr section will not be generated. To make it work
with Gnu ld, we would have to leave the R_NONE relocations in, but I
think it's better to drop the relocations entirely. I'd hope that if
you're doing a -r link with gold, you'll also do the final link with
gold.
gold/
PR gold/19002
* ehframe.cc (Eh_frame::read_fde): Check for dropped functions.
* testsuite/Makefile.am (eh_test_2): New test.
* testsuite/Makefile.in: Regenerate.
* testsuite/eh_test_2.sh: New test script.
* testsuite/eh_test_a.cc (bar): Make it comdat.
* testsuite/eh_test_b.cc (bar): Add a duplicate copy.
2016-03-21 10:15:56 +08:00
|
|
|
int pc_size = 0;
|
|
|
|
switch (cie->fde_encoding() & 7)
|
|
|
|
{
|
|
|
|
case elfcpp::DW_EH_PE_udata2:
|
|
|
|
pc_size = 2;
|
|
|
|
break;
|
|
|
|
case elfcpp::DW_EH_PE_udata4:
|
|
|
|
pc_size = 4;
|
|
|
|
break;
|
|
|
|
case elfcpp::DW_EH_PE_udata8:
|
|
|
|
gold_assert(size == 64);
|
|
|
|
pc_size = 8;
|
|
|
|
break;
|
|
|
|
case elfcpp::DW_EH_PE_absptr:
|
|
|
|
pc_size = size == 32 ? 4 : 8;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// All other cases were rejected in Eh_frame::read_cie.
|
|
|
|
gold_unreachable();
|
|
|
|
}
|
|
|
|
|
2007-11-09 15:00:15 +08:00
|
|
|
// The FDE should start with a reloc to the start of the code which
|
|
|
|
// it describes.
|
|
|
|
if (relocs->advance(pfde - pcontents) > 0)
|
|
|
|
return false;
|
|
|
|
if (relocs->next_offset() != pfde - pcontents)
|
Fix problem where gold cannot build .eh_frame_hdr from ld -r output.
When running ld -r on objects that have comdat groups, when gold
deduplicates a function in a comdat group, it removes the relocations
from the EH information that referred to the dropped copy of the function.
When running a final link using the result of the -r link, the missing
relocation cause it to fail to recognize the FDE for the dropped
function.
This patch improves gold's FDE scanning to take into account the
possibility that an FDE corresponds to a dropped function, and drops
that FDE as well.
Gnu ld, on the other hand, leaves the relocations in the ld -r output,
but makes them R_NONE with an r_sym field of 0. This was sufficient to
let both linkers recognize the FDE properly.
With this fix, if you do an ld -r with gold, then do the final link with
Gnu ld, the .eh_frame_hdr section will not be generated. To make it work
with Gnu ld, we would have to leave the R_NONE relocations in, but I
think it's better to drop the relocations entirely. I'd hope that if
you're doing a -r link with gold, you'll also do the final link with
gold.
gold/
PR gold/19002
* ehframe.cc (Eh_frame::read_fde): Check for dropped functions.
* testsuite/Makefile.am (eh_test_2): New test.
* testsuite/Makefile.in: Regenerate.
* testsuite/eh_test_2.sh: New test script.
* testsuite/eh_test_a.cc (bar): Make it comdat.
* testsuite/eh_test_b.cc (bar): Add a duplicate copy.
2016-03-21 10:15:56 +08:00
|
|
|
{
|
|
|
|
// In an object produced by a relocatable link, gold may have
|
|
|
|
// discarded a COMDAT group in the previous link, but not the
|
|
|
|
// corresponding FDEs. In that case, gold will have discarded
|
|
|
|
// the relocations, so the FDE will have a non-relocatable zero
|
|
|
|
// (regardless of whether the PC encoding is absolute, pc-relative,
|
|
|
|
// or data-relative) instead of a pointer to the start of the code.
|
|
|
|
|
|
|
|
uint64_t pc_value = 0;
|
|
|
|
switch (pc_size)
|
|
|
|
{
|
|
|
|
case 2:
|
|
|
|
pc_value = elfcpp::Swap<16, big_endian>::readval(pfde);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
pc_value = elfcpp::Swap<32, big_endian>::readval(pfde);
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
pc_value = elfcpp::Swap_unaligned<64, big_endian>::readval(pfde);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
gold_unreachable();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pc_value == 0)
|
|
|
|
{
|
|
|
|
// This FDE applies to a discarded function. We
|
|
|
|
// can discard this FDE.
|
|
|
|
object->add_merge_mapping(this, shndx, (pfde - 8) - pcontents,
|
|
|
|
pfdeend - (pfde - 8), -1);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, reject the FDE.
|
|
|
|
return false;
|
|
|
|
}
|
2007-11-09 15:00:15 +08:00
|
|
|
|
|
|
|
unsigned int symndx = relocs->next_symndx();
|
|
|
|
if (symndx == -1U)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// There can be another reloc in the FDE, if the CIE specifies an
|
|
|
|
// LSDA (language specific data area). We currently don't care. We
|
|
|
|
// will care later if we want to optimize the LSDA from an absolute
|
|
|
|
// pointer to a PC relative offset when generating a shared library.
|
|
|
|
relocs->advance(pfdeend - pcontents);
|
|
|
|
|
2016-02-26 23:50:15 +08:00
|
|
|
// Find the section index for code that this FDE describes.
|
|
|
|
// If we have discarded the section, we can also discard the FDE.
|
2007-11-09 15:00:15 +08:00
|
|
|
unsigned int fde_shndx;
|
|
|
|
const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
|
|
|
|
if (symndx >= symbols_size / sym_size)
|
|
|
|
return false;
|
|
|
|
elfcpp::Sym<size, big_endian> sym(symbols + symndx * sym_size);
|
2008-04-20 02:30:58 +08:00
|
|
|
bool is_ordinary;
|
|
|
|
fde_shndx = object->adjust_sym_shndx(symndx, sym.get_st_shndx(),
|
|
|
|
&is_ordinary);
|
2016-02-26 23:50:15 +08:00
|
|
|
bool is_discarded = (is_ordinary
|
|
|
|
&& fde_shndx != elfcpp::SHN_UNDEF
|
|
|
|
&& fde_shndx < object->shnum()
|
|
|
|
&& !object->is_section_included(fde_shndx));
|
|
|
|
|
|
|
|
// Fetch the address range field from the FDE. The offset and size
|
|
|
|
// of the field depends on the PC encoding given in the CIE, but
|
|
|
|
// it is always an absolute value. If the address range is 0, this
|
|
|
|
// FDE corresponds to a function that was discarded during optimization
|
|
|
|
// (too late to discard the corresponding FDE).
|
|
|
|
uint64_t address_range = 0;
|
|
|
|
switch (pc_size)
|
|
|
|
{
|
Fix problem where gold cannot build .eh_frame_hdr from ld -r output.
When running ld -r on objects that have comdat groups, when gold
deduplicates a function in a comdat group, it removes the relocations
from the EH information that referred to the dropped copy of the function.
When running a final link using the result of the -r link, the missing
relocation cause it to fail to recognize the FDE for the dropped
function.
This patch improves gold's FDE scanning to take into account the
possibility that an FDE corresponds to a dropped function, and drops
that FDE as well.
Gnu ld, on the other hand, leaves the relocations in the ld -r output,
but makes them R_NONE with an r_sym field of 0. This was sufficient to
let both linkers recognize the FDE properly.
With this fix, if you do an ld -r with gold, then do the final link with
Gnu ld, the .eh_frame_hdr section will not be generated. To make it work
with Gnu ld, we would have to leave the R_NONE relocations in, but I
think it's better to drop the relocations entirely. I'd hope that if
you're doing a -r link with gold, you'll also do the final link with
gold.
gold/
PR gold/19002
* ehframe.cc (Eh_frame::read_fde): Check for dropped functions.
* testsuite/Makefile.am (eh_test_2): New test.
* testsuite/Makefile.in: Regenerate.
* testsuite/eh_test_2.sh: New test script.
* testsuite/eh_test_a.cc (bar): Make it comdat.
* testsuite/eh_test_b.cc (bar): Add a duplicate copy.
2016-03-21 10:15:56 +08:00
|
|
|
case 2:
|
2016-02-26 23:50:15 +08:00
|
|
|
address_range = elfcpp::Swap<16, big_endian>::readval(pfde + 2);
|
|
|
|
break;
|
Fix problem where gold cannot build .eh_frame_hdr from ld -r output.
When running ld -r on objects that have comdat groups, when gold
deduplicates a function in a comdat group, it removes the relocations
from the EH information that referred to the dropped copy of the function.
When running a final link using the result of the -r link, the missing
relocation cause it to fail to recognize the FDE for the dropped
function.
This patch improves gold's FDE scanning to take into account the
possibility that an FDE corresponds to a dropped function, and drops
that FDE as well.
Gnu ld, on the other hand, leaves the relocations in the ld -r output,
but makes them R_NONE with an r_sym field of 0. This was sufficient to
let both linkers recognize the FDE properly.
With this fix, if you do an ld -r with gold, then do the final link with
Gnu ld, the .eh_frame_hdr section will not be generated. To make it work
with Gnu ld, we would have to leave the R_NONE relocations in, but I
think it's better to drop the relocations entirely. I'd hope that if
you're doing a -r link with gold, you'll also do the final link with
gold.
gold/
PR gold/19002
* ehframe.cc (Eh_frame::read_fde): Check for dropped functions.
* testsuite/Makefile.am (eh_test_2): New test.
* testsuite/Makefile.in: Regenerate.
* testsuite/eh_test_2.sh: New test script.
* testsuite/eh_test_a.cc (bar): Make it comdat.
* testsuite/eh_test_b.cc (bar): Add a duplicate copy.
2016-03-21 10:15:56 +08:00
|
|
|
case 4:
|
2016-02-26 23:50:15 +08:00
|
|
|
address_range = elfcpp::Swap<32, big_endian>::readval(pfde + 4);
|
|
|
|
break;
|
Fix problem where gold cannot build .eh_frame_hdr from ld -r output.
When running ld -r on objects that have comdat groups, when gold
deduplicates a function in a comdat group, it removes the relocations
from the EH information that referred to the dropped copy of the function.
When running a final link using the result of the -r link, the missing
relocation cause it to fail to recognize the FDE for the dropped
function.
This patch improves gold's FDE scanning to take into account the
possibility that an FDE corresponds to a dropped function, and drops
that FDE as well.
Gnu ld, on the other hand, leaves the relocations in the ld -r output,
but makes them R_NONE with an r_sym field of 0. This was sufficient to
let both linkers recognize the FDE properly.
With this fix, if you do an ld -r with gold, then do the final link with
Gnu ld, the .eh_frame_hdr section will not be generated. To make it work
with Gnu ld, we would have to leave the R_NONE relocations in, but I
think it's better to drop the relocations entirely. I'd hope that if
you're doing a -r link with gold, you'll also do the final link with
gold.
gold/
PR gold/19002
* ehframe.cc (Eh_frame::read_fde): Check for dropped functions.
* testsuite/Makefile.am (eh_test_2): New test.
* testsuite/Makefile.in: Regenerate.
* testsuite/eh_test_2.sh: New test script.
* testsuite/eh_test_a.cc (bar): Make it comdat.
* testsuite/eh_test_b.cc (bar): Add a duplicate copy.
2016-03-21 10:15:56 +08:00
|
|
|
case 8:
|
2016-02-26 23:50:15 +08:00
|
|
|
address_range = elfcpp::Swap_unaligned<64, big_endian>::readval(pfde + 8);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
gold_unreachable();
|
|
|
|
}
|
2007-11-09 15:00:15 +08:00
|
|
|
|
2016-02-26 23:50:15 +08:00
|
|
|
if (is_discarded || address_range == 0)
|
2007-11-09 15:00:15 +08:00
|
|
|
{
|
2016-02-26 23:50:15 +08:00
|
|
|
// This FDE applies to a discarded function. We
|
2007-11-09 15:00:15 +08:00
|
|
|
// can discard this FDE.
|
2015-03-05 07:10:18 +08:00
|
|
|
object->add_merge_mapping(this, shndx, (pfde - 8) - pcontents,
|
|
|
|
pfdeend - (pfde - 8), -1);
|
2007-11-09 15:00:15 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
cie->add_fde(new Fde(object, shndx, (pfde - 8) - pcontents,
|
|
|
|
pfde, pfdeend - pfde));
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
PR gold/12571
* options.h (class General_options): Add
--ld-generated-unwind-info.
* ehframe.cc (Fde::write): Add address parameter. Change all
callers. If associated with PLT, fill in address and size.
(Cie::set_output_offset): Only add merge mapping if there is an
object.
(Cie::write): Add address parameter. Change all callers.
(Eh_frame::add_ehframe_for_plt): New function.
* ehframe.h (class Fde): Update declarations. Move shndx_ and
input_offset_ fields into union u_, with new plt field.
(Fde::Fde): Adjust for new union field.
(Fde::Fde) [Output_data version]: New constructor.
(Fde::add_mapping): Only add merge mapping if there is an object.
(class Cie): Update declarations.
(class Eh_frame): Declare add_ehframe_for_plt.
* layout.cc (Layout::layout_eh_frame): Break out code into
make_eh_frame_section, and call it.
(Layout::make_eh_frame_section): New function.
(Layout::add_eh_frame_for_plt): New function.
* layout.h (class Layout): Update declarations.
* merge.cc (Merge_map::add_mapping): Add assertion.
* i386.cc: Include "dwarf.h".
(class Output_data_plt_i386): Make first_plt_entry,
dyn_first_plt_entry, exec_plt_entry, and dyn_plt_entry const. Add
plt_eh_frame_cie_size, plt_eh_frame_fde_size, plt_eh_frame_cie,
and plt_eh_frame_fde.
(Output_data_plt_i386::Output_data_plt_i386): Align to 16-byte
boundary. Call add_eh_frame_for_plt if appropriate.
* x86_64.cc: Include "dwarf.h".
(class Output_data_plt_x86_64): Align to 16-byte boundary. Make
first_plt_entry, plt_entry and tlsdesc_plt_entry const. Add
plt_eh_frame_cie_size, plt_eh_frame_fde_size, plt_eh_frame_cie,
and plt_eh_frame_fde.
(Output_data_plt_x86_64::init): Call add_eh_frame_for_plt if
appropriate.
2011-07-02 06:05:01 +08:00
|
|
|
// Add unwind information for a PLT.
|
|
|
|
|
|
|
|
void
|
|
|
|
Eh_frame::add_ehframe_for_plt(Output_data* plt, const unsigned char* cie_data,
|
|
|
|
size_t cie_length, const unsigned char* fde_data,
|
|
|
|
size_t fde_length)
|
|
|
|
{
|
|
|
|
Cie cie(NULL, 0, 0, elfcpp::DW_EH_PE_pcrel | elfcpp::DW_EH_PE_sdata4, "",
|
|
|
|
cie_data, cie_length);
|
|
|
|
Cie_offsets::iterator find_cie = this->cie_offsets_.find(&cie);
|
|
|
|
Cie* pcie;
|
|
|
|
if (find_cie != this->cie_offsets_.end())
|
|
|
|
pcie = *find_cie;
|
|
|
|
else
|
|
|
|
{
|
* target.h (Target::plt_fde_location, do_plt_fde_location): Declare.
* target.cc (Target::do_plt_fde_location): New function.
* ehframe.h (class FDE): Add post_map field to u_.from_linker,
accessor function, and constructor param.
(struct Post_fde, Post_fdes): Declare.
(Cie::write): Add post_fdes param.
* ehframe.cc (Fde::write): Use plt_fde_location.
(struct Post_fde): Define.
(Cie::write): Stash FDEs added post merge mapping.
(Eh_frame::add_ehframe_for_plt): Assert no new CIEs after mapping.
Adjust Fde constructor call. Bump final_data_size_ for post map FDEs.
(Eh_frame::do_sized_write): Arrange to write post map FDES after
other FDEs.
* powerpc.cc (Target_powerpc::do_plt_fde_location): New function.
(Target_powerpc::has_glink): New function.
(Target_powerpc::do_relax): Add eh_frame info for stubs.
(struct Eh_cie, eh_frame_cie, glink_eh_frame_fde_64,
glink_eh_frame_fde_32, default_fde): New data.
(Stub_table::eh_frame_added_): New var.
(Stub_table::find_long_branch_entry, stub_address, stub_offset):
Make const.
(Stub_table::add_eh_frame): New function.
(Output_data_glink::add_eh_frame): New function.
(Target_powerpc::make_glink_section): Call add_eh_frame.
2013-02-28 07:11:56 +08:00
|
|
|
gold_assert(!this->mappings_are_done_);
|
PR gold/12571
* options.h (class General_options): Add
--ld-generated-unwind-info.
* ehframe.cc (Fde::write): Add address parameter. Change all
callers. If associated with PLT, fill in address and size.
(Cie::set_output_offset): Only add merge mapping if there is an
object.
(Cie::write): Add address parameter. Change all callers.
(Eh_frame::add_ehframe_for_plt): New function.
* ehframe.h (class Fde): Update declarations. Move shndx_ and
input_offset_ fields into union u_, with new plt field.
(Fde::Fde): Adjust for new union field.
(Fde::Fde) [Output_data version]: New constructor.
(Fde::add_mapping): Only add merge mapping if there is an object.
(class Cie): Update declarations.
(class Eh_frame): Declare add_ehframe_for_plt.
* layout.cc (Layout::layout_eh_frame): Break out code into
make_eh_frame_section, and call it.
(Layout::make_eh_frame_section): New function.
(Layout::add_eh_frame_for_plt): New function.
* layout.h (class Layout): Update declarations.
* merge.cc (Merge_map::add_mapping): Add assertion.
* i386.cc: Include "dwarf.h".
(class Output_data_plt_i386): Make first_plt_entry,
dyn_first_plt_entry, exec_plt_entry, and dyn_plt_entry const. Add
plt_eh_frame_cie_size, plt_eh_frame_fde_size, plt_eh_frame_cie,
and plt_eh_frame_fde.
(Output_data_plt_i386::Output_data_plt_i386): Align to 16-byte
boundary. Call add_eh_frame_for_plt if appropriate.
* x86_64.cc: Include "dwarf.h".
(class Output_data_plt_x86_64): Align to 16-byte boundary. Make
first_plt_entry, plt_entry and tlsdesc_plt_entry const. Add
plt_eh_frame_cie_size, plt_eh_frame_fde_size, plt_eh_frame_cie,
and plt_eh_frame_fde.
(Output_data_plt_x86_64::init): Call add_eh_frame_for_plt if
appropriate.
2011-07-02 06:05:01 +08:00
|
|
|
pcie = new Cie(cie);
|
|
|
|
this->cie_offsets_.insert(pcie);
|
|
|
|
}
|
|
|
|
|
* target.h (Target::plt_fde_location, do_plt_fde_location): Declare.
* target.cc (Target::do_plt_fde_location): New function.
* ehframe.h (class FDE): Add post_map field to u_.from_linker,
accessor function, and constructor param.
(struct Post_fde, Post_fdes): Declare.
(Cie::write): Add post_fdes param.
* ehframe.cc (Fde::write): Use plt_fde_location.
(struct Post_fde): Define.
(Cie::write): Stash FDEs added post merge mapping.
(Eh_frame::add_ehframe_for_plt): Assert no new CIEs after mapping.
Adjust Fde constructor call. Bump final_data_size_ for post map FDEs.
(Eh_frame::do_sized_write): Arrange to write post map FDES after
other FDEs.
* powerpc.cc (Target_powerpc::do_plt_fde_location): New function.
(Target_powerpc::has_glink): New function.
(Target_powerpc::do_relax): Add eh_frame info for stubs.
(struct Eh_cie, eh_frame_cie, glink_eh_frame_fde_64,
glink_eh_frame_fde_32, default_fde): New data.
(Stub_table::eh_frame_added_): New var.
(Stub_table::find_long_branch_entry, stub_address, stub_offset):
Make const.
(Stub_table::add_eh_frame): New function.
(Output_data_glink::add_eh_frame): New function.
(Target_powerpc::make_glink_section): Call add_eh_frame.
2013-02-28 07:11:56 +08:00
|
|
|
Fde* fde = new Fde(plt, fde_data, fde_length, this->mappings_are_done_);
|
PR gold/12571
* options.h (class General_options): Add
--ld-generated-unwind-info.
* ehframe.cc (Fde::write): Add address parameter. Change all
callers. If associated with PLT, fill in address and size.
(Cie::set_output_offset): Only add merge mapping if there is an
object.
(Cie::write): Add address parameter. Change all callers.
(Eh_frame::add_ehframe_for_plt): New function.
* ehframe.h (class Fde): Update declarations. Move shndx_ and
input_offset_ fields into union u_, with new plt field.
(Fde::Fde): Adjust for new union field.
(Fde::Fde) [Output_data version]: New constructor.
(Fde::add_mapping): Only add merge mapping if there is an object.
(class Cie): Update declarations.
(class Eh_frame): Declare add_ehframe_for_plt.
* layout.cc (Layout::layout_eh_frame): Break out code into
make_eh_frame_section, and call it.
(Layout::make_eh_frame_section): New function.
(Layout::add_eh_frame_for_plt): New function.
* layout.h (class Layout): Update declarations.
* merge.cc (Merge_map::add_mapping): Add assertion.
* i386.cc: Include "dwarf.h".
(class Output_data_plt_i386): Make first_plt_entry,
dyn_first_plt_entry, exec_plt_entry, and dyn_plt_entry const. Add
plt_eh_frame_cie_size, plt_eh_frame_fde_size, plt_eh_frame_cie,
and plt_eh_frame_fde.
(Output_data_plt_i386::Output_data_plt_i386): Align to 16-byte
boundary. Call add_eh_frame_for_plt if appropriate.
* x86_64.cc: Include "dwarf.h".
(class Output_data_plt_x86_64): Align to 16-byte boundary. Make
first_plt_entry, plt_entry and tlsdesc_plt_entry const. Add
plt_eh_frame_cie_size, plt_eh_frame_fde_size, plt_eh_frame_cie,
and plt_eh_frame_fde.
(Output_data_plt_x86_64::init): Call add_eh_frame_for_plt if
appropriate.
2011-07-02 06:05:01 +08:00
|
|
|
pcie->add_fde(fde);
|
* target.h (Target::plt_fde_location, do_plt_fde_location): Declare.
* target.cc (Target::do_plt_fde_location): New function.
* ehframe.h (class FDE): Add post_map field to u_.from_linker,
accessor function, and constructor param.
(struct Post_fde, Post_fdes): Declare.
(Cie::write): Add post_fdes param.
* ehframe.cc (Fde::write): Use plt_fde_location.
(struct Post_fde): Define.
(Cie::write): Stash FDEs added post merge mapping.
(Eh_frame::add_ehframe_for_plt): Assert no new CIEs after mapping.
Adjust Fde constructor call. Bump final_data_size_ for post map FDEs.
(Eh_frame::do_sized_write): Arrange to write post map FDES after
other FDEs.
* powerpc.cc (Target_powerpc::do_plt_fde_location): New function.
(Target_powerpc::has_glink): New function.
(Target_powerpc::do_relax): Add eh_frame info for stubs.
(struct Eh_cie, eh_frame_cie, glink_eh_frame_fde_64,
glink_eh_frame_fde_32, default_fde): New data.
(Stub_table::eh_frame_added_): New var.
(Stub_table::find_long_branch_entry, stub_address, stub_offset):
Make const.
(Stub_table::add_eh_frame): New function.
(Output_data_glink::add_eh_frame): New function.
(Target_powerpc::make_glink_section): Call add_eh_frame.
2013-02-28 07:11:56 +08:00
|
|
|
|
|
|
|
if (this->mappings_are_done_)
|
|
|
|
this->final_data_size_ += align_address(fde_length + 8, this->addralign());
|
PR gold/12571
* options.h (class General_options): Add
--ld-generated-unwind-info.
* ehframe.cc (Fde::write): Add address parameter. Change all
callers. If associated with PLT, fill in address and size.
(Cie::set_output_offset): Only add merge mapping if there is an
object.
(Cie::write): Add address parameter. Change all callers.
(Eh_frame::add_ehframe_for_plt): New function.
* ehframe.h (class Fde): Update declarations. Move shndx_ and
input_offset_ fields into union u_, with new plt field.
(Fde::Fde): Adjust for new union field.
(Fde::Fde) [Output_data version]: New constructor.
(Fde::add_mapping): Only add merge mapping if there is an object.
(class Cie): Update declarations.
(class Eh_frame): Declare add_ehframe_for_plt.
* layout.cc (Layout::layout_eh_frame): Break out code into
make_eh_frame_section, and call it.
(Layout::make_eh_frame_section): New function.
(Layout::add_eh_frame_for_plt): New function.
* layout.h (class Layout): Update declarations.
* merge.cc (Merge_map::add_mapping): Add assertion.
* i386.cc: Include "dwarf.h".
(class Output_data_plt_i386): Make first_plt_entry,
dyn_first_plt_entry, exec_plt_entry, and dyn_plt_entry const. Add
plt_eh_frame_cie_size, plt_eh_frame_fde_size, plt_eh_frame_cie,
and plt_eh_frame_fde.
(Output_data_plt_i386::Output_data_plt_i386): Align to 16-byte
boundary. Call add_eh_frame_for_plt if appropriate.
* x86_64.cc: Include "dwarf.h".
(class Output_data_plt_x86_64): Align to 16-byte boundary. Make
first_plt_entry, plt_entry and tlsdesc_plt_entry const. Add
plt_eh_frame_cie_size, plt_eh_frame_fde_size, plt_eh_frame_cie,
and plt_eh_frame_fde.
(Output_data_plt_x86_64::init): Call add_eh_frame_for_plt if
appropriate.
2011-07-02 06:05:01 +08:00
|
|
|
}
|
|
|
|
|
[GOLD] PowerPC notoc eh_frame
When generating notoc call and branch stubs without the benefit of
pc-relative insns, the stubs need to use LR to access the run time PC.
All LR changes must be described in .eh_frame if we're to support
unwinding through asynchronous exceptions. That's what this patch
does.
The patch has gone through way too many iterations. At first I
attempted to add multiple FDEs, one for each stub. That ran into
difficulties with do_plt_fde_location which is only capable of setting
the address of a single FDE per Output_data section, and with removing
any FDEs added on a previous do_relax pass. Removing FDEs (git commit
be897fb774) went overboard in matching the FDE contents. That means
either stashing the contents created for add_eh_frame_for_plt to use
when calling remove_eh_frame_for_plt, or recreating contents on the
fly (*) just to remove FDEs. In fact, FDE content matching is quite
unnecesary. FDEs added by a previous do_relax pass are those with
u_.from_linker.post_map set. So they can easily be recognised just by
looking at that flag. This patch keeps that part of the multiple FDE
changes.
In the end I went for just one FDE per stub group to describe the call
stubs. That's reasonably efficient for the common case of only
needing to describe the __tls_get_addr_opt call stub. We don't expect
to be making many calls using notoc stubs without pc-relative insns.
*) Which has it's own set of problems. The contents must be recreated
using the old stub layout, but .eh_frame size can affect stub
requirements so you need to temporarily keep the old .eh_frame size
when creating new stubs, then reset .eh_frame size before adding new
FDEs.
* ehframe.cc (Fde::operator==): Delete.
(Cie::remove_fde): Delete.
(Eh_frame::remove_ehframe_for_plt): Delete fde_data and fde_length
parameters. Remove all post-map plt FDEs.
* ehframe.h (Fde:post_map): Make const, add variant to compare plt.
(Fde::operator==): Delete.
(Cie::remove_fde): Implement here.
(Cie::last_fde): New accessor.
(Eh_frame::remove_ehframe_for_plt): Update prototype.
* layout.cc (Layout::remove_eh_frame_for_plt): Delete fde_data and
fde_length parameters.
* layout.h (Layout::remove_eh_frame_for_plt): Update prototype.
* powerpc.cc (Stub_table::tls_get_addr_opt_bctrl_): Delete.
(Stub_table::plt_fde_len_, plt_fde_, init_plt_fde): Delete.
(Stub_table::add_plt_call_entry): Don't set tls_get_addr_opt_bctrl_.
(eh_advance): New function.
(stub_sort): New function.
(Stub_table::add_eh_frame): Emit eh_frame for notoc plt calls and
branches as well as __tls_get_addr_opt plt call stub.
(Stub_table::remove_eh_frame): Update to suit.
2019-07-01 13:07:49 +08:00
|
|
|
// Remove all post-map unwind information for a PLT.
|
[GOLD] PowerPC recreate eh_frame for stubs on each relax pass
There is a very small but non-zero probability that a stub group
contains stubs on one relax pass, but does not on the next. In that
case we would get an FDE covering a zero length address range.
(Actually, it's even worse. Alignment padding for stubs can mean the
address for the non-existent stubs is past the end of the original
section to which stubs are attached, and due to the way
do_plt_fde_location calculates the length we can get a negative
length.) Fixing this properly requires removing the FDE.
Also, I have been implementing the __tls_get_addr_opt support for
gold, and that stub needs something other than the default FDE. The
necessary FDE will depend on the offset to the __tls_get_addr_opt
stub, which of course can change during relaxation. That means at the
very least, rewriting the FDE on each pass, possibly changing the FDE
size. I think that is better done by completely recreating PLT
eh_frame FDEs.
* ehframe.cc (Fde::operator==): New.
(Cie::remove_fde, Eh_frame::remove_ehframe_for_plt): New.
* ehframe.h (Fde::operator==): Declare.
(Cie::remove_fde, Eh_frame::remove_ehframe_for_plt): Likewise.
* layout.cc (Layout::remove_eh_frame_for_plt): New.
* layout.h (Layout::remove_eh_frame_for_plt): Declare.
* powerpc.cc (Target_powerpc::do_relax): Remove old eh_frame FDEs.
(Stub_table::add_eh_frame): Delete eh_frame_added_ condition.
Don't add eh_frame for empty stub section.
(Stub_table::remove_eh_frame): New.
2017-08-01 12:38:53 +08:00
|
|
|
|
|
|
|
void
|
|
|
|
Eh_frame::remove_ehframe_for_plt(Output_data* plt,
|
|
|
|
const unsigned char* cie_data,
|
[GOLD] PowerPC notoc eh_frame
When generating notoc call and branch stubs without the benefit of
pc-relative insns, the stubs need to use LR to access the run time PC.
All LR changes must be described in .eh_frame if we're to support
unwinding through asynchronous exceptions. That's what this patch
does.
The patch has gone through way too many iterations. At first I
attempted to add multiple FDEs, one for each stub. That ran into
difficulties with do_plt_fde_location which is only capable of setting
the address of a single FDE per Output_data section, and with removing
any FDEs added on a previous do_relax pass. Removing FDEs (git commit
be897fb774) went overboard in matching the FDE contents. That means
either stashing the contents created for add_eh_frame_for_plt to use
when calling remove_eh_frame_for_plt, or recreating contents on the
fly (*) just to remove FDEs. In fact, FDE content matching is quite
unnecesary. FDEs added by a previous do_relax pass are those with
u_.from_linker.post_map set. So they can easily be recognised just by
looking at that flag. This patch keeps that part of the multiple FDE
changes.
In the end I went for just one FDE per stub group to describe the call
stubs. That's reasonably efficient for the common case of only
needing to describe the __tls_get_addr_opt call stub. We don't expect
to be making many calls using notoc stubs without pc-relative insns.
*) Which has it's own set of problems. The contents must be recreated
using the old stub layout, but .eh_frame size can affect stub
requirements so you need to temporarily keep the old .eh_frame size
when creating new stubs, then reset .eh_frame size before adding new
FDEs.
* ehframe.cc (Fde::operator==): Delete.
(Cie::remove_fde): Delete.
(Eh_frame::remove_ehframe_for_plt): Delete fde_data and fde_length
parameters. Remove all post-map plt FDEs.
* ehframe.h (Fde:post_map): Make const, add variant to compare plt.
(Fde::operator==): Delete.
(Cie::remove_fde): Implement here.
(Cie::last_fde): New accessor.
(Eh_frame::remove_ehframe_for_plt): Update prototype.
* layout.cc (Layout::remove_eh_frame_for_plt): Delete fde_data and
fde_length parameters.
* layout.h (Layout::remove_eh_frame_for_plt): Update prototype.
* powerpc.cc (Stub_table::tls_get_addr_opt_bctrl_): Delete.
(Stub_table::plt_fde_len_, plt_fde_, init_plt_fde): Delete.
(Stub_table::add_plt_call_entry): Don't set tls_get_addr_opt_bctrl_.
(eh_advance): New function.
(stub_sort): New function.
(Stub_table::add_eh_frame): Emit eh_frame for notoc plt calls and
branches as well as __tls_get_addr_opt plt call stub.
(Stub_table::remove_eh_frame): Update to suit.
2019-07-01 13:07:49 +08:00
|
|
|
size_t cie_length)
|
[GOLD] PowerPC recreate eh_frame for stubs on each relax pass
There is a very small but non-zero probability that a stub group
contains stubs on one relax pass, but does not on the next. In that
case we would get an FDE covering a zero length address range.
(Actually, it's even worse. Alignment padding for stubs can mean the
address for the non-existent stubs is past the end of the original
section to which stubs are attached, and due to the way
do_plt_fde_location calculates the length we can get a negative
length.) Fixing this properly requires removing the FDE.
Also, I have been implementing the __tls_get_addr_opt support for
gold, and that stub needs something other than the default FDE. The
necessary FDE will depend on the offset to the __tls_get_addr_opt
stub, which of course can change during relaxation. That means at the
very least, rewriting the FDE on each pass, possibly changing the FDE
size. I think that is better done by completely recreating PLT
eh_frame FDEs.
* ehframe.cc (Fde::operator==): New.
(Cie::remove_fde, Eh_frame::remove_ehframe_for_plt): New.
* ehframe.h (Fde::operator==): Declare.
(Cie::remove_fde, Eh_frame::remove_ehframe_for_plt): Likewise.
* layout.cc (Layout::remove_eh_frame_for_plt): New.
* layout.h (Layout::remove_eh_frame_for_plt): Declare.
* powerpc.cc (Target_powerpc::do_relax): Remove old eh_frame FDEs.
(Stub_table::add_eh_frame): Delete eh_frame_added_ condition.
Don't add eh_frame for empty stub section.
(Stub_table::remove_eh_frame): New.
2017-08-01 12:38:53 +08:00
|
|
|
{
|
[GOLD] PowerPC notoc eh_frame
When generating notoc call and branch stubs without the benefit of
pc-relative insns, the stubs need to use LR to access the run time PC.
All LR changes must be described in .eh_frame if we're to support
unwinding through asynchronous exceptions. That's what this patch
does.
The patch has gone through way too many iterations. At first I
attempted to add multiple FDEs, one for each stub. That ran into
difficulties with do_plt_fde_location which is only capable of setting
the address of a single FDE per Output_data section, and with removing
any FDEs added on a previous do_relax pass. Removing FDEs (git commit
be897fb774) went overboard in matching the FDE contents. That means
either stashing the contents created for add_eh_frame_for_plt to use
when calling remove_eh_frame_for_plt, or recreating contents on the
fly (*) just to remove FDEs. In fact, FDE content matching is quite
unnecesary. FDEs added by a previous do_relax pass are those with
u_.from_linker.post_map set. So they can easily be recognised just by
looking at that flag. This patch keeps that part of the multiple FDE
changes.
In the end I went for just one FDE per stub group to describe the call
stubs. That's reasonably efficient for the common case of only
needing to describe the __tls_get_addr_opt call stub. We don't expect
to be making many calls using notoc stubs without pc-relative insns.
*) Which has it's own set of problems. The contents must be recreated
using the old stub layout, but .eh_frame size can affect stub
requirements so you need to temporarily keep the old .eh_frame size
when creating new stubs, then reset .eh_frame size before adding new
FDEs.
* ehframe.cc (Fde::operator==): Delete.
(Cie::remove_fde): Delete.
(Eh_frame::remove_ehframe_for_plt): Delete fde_data and fde_length
parameters. Remove all post-map plt FDEs.
* ehframe.h (Fde:post_map): Make const, add variant to compare plt.
(Fde::operator==): Delete.
(Cie::remove_fde): Implement here.
(Cie::last_fde): New accessor.
(Eh_frame::remove_ehframe_for_plt): Update prototype.
* layout.cc (Layout::remove_eh_frame_for_plt): Delete fde_data and
fde_length parameters.
* layout.h (Layout::remove_eh_frame_for_plt): Update prototype.
* powerpc.cc (Stub_table::tls_get_addr_opt_bctrl_): Delete.
(Stub_table::plt_fde_len_, plt_fde_, init_plt_fde): Delete.
(Stub_table::add_plt_call_entry): Don't set tls_get_addr_opt_bctrl_.
(eh_advance): New function.
(stub_sort): New function.
(Stub_table::add_eh_frame): Emit eh_frame for notoc plt calls and
branches as well as __tls_get_addr_opt plt call stub.
(Stub_table::remove_eh_frame): Update to suit.
2019-07-01 13:07:49 +08:00
|
|
|
if (!this->mappings_are_done_)
|
|
|
|
return;
|
|
|
|
|
[GOLD] PowerPC recreate eh_frame for stubs on each relax pass
There is a very small but non-zero probability that a stub group
contains stubs on one relax pass, but does not on the next. In that
case we would get an FDE covering a zero length address range.
(Actually, it's even worse. Alignment padding for stubs can mean the
address for the non-existent stubs is past the end of the original
section to which stubs are attached, and due to the way
do_plt_fde_location calculates the length we can get a negative
length.) Fixing this properly requires removing the FDE.
Also, I have been implementing the __tls_get_addr_opt support for
gold, and that stub needs something other than the default FDE. The
necessary FDE will depend on the offset to the __tls_get_addr_opt
stub, which of course can change during relaxation. That means at the
very least, rewriting the FDE on each pass, possibly changing the FDE
size. I think that is better done by completely recreating PLT
eh_frame FDEs.
* ehframe.cc (Fde::operator==): New.
(Cie::remove_fde, Eh_frame::remove_ehframe_for_plt): New.
* ehframe.h (Fde::operator==): Declare.
(Cie::remove_fde, Eh_frame::remove_ehframe_for_plt): Likewise.
* layout.cc (Layout::remove_eh_frame_for_plt): New.
* layout.h (Layout::remove_eh_frame_for_plt): Declare.
* powerpc.cc (Target_powerpc::do_relax): Remove old eh_frame FDEs.
(Stub_table::add_eh_frame): Delete eh_frame_added_ condition.
Don't add eh_frame for empty stub section.
(Stub_table::remove_eh_frame): New.
2017-08-01 12:38:53 +08:00
|
|
|
Cie cie(NULL, 0, 0, elfcpp::DW_EH_PE_pcrel | elfcpp::DW_EH_PE_sdata4, "",
|
|
|
|
cie_data, cie_length);
|
|
|
|
Cie_offsets::iterator find_cie = this->cie_offsets_.find(&cie);
|
|
|
|
gold_assert (find_cie != this->cie_offsets_.end());
|
|
|
|
Cie* pcie = *find_cie;
|
|
|
|
|
[GOLD] PowerPC notoc eh_frame
When generating notoc call and branch stubs without the benefit of
pc-relative insns, the stubs need to use LR to access the run time PC.
All LR changes must be described in .eh_frame if we're to support
unwinding through asynchronous exceptions. That's what this patch
does.
The patch has gone through way too many iterations. At first I
attempted to add multiple FDEs, one for each stub. That ran into
difficulties with do_plt_fde_location which is only capable of setting
the address of a single FDE per Output_data section, and with removing
any FDEs added on a previous do_relax pass. Removing FDEs (git commit
be897fb774) went overboard in matching the FDE contents. That means
either stashing the contents created for add_eh_frame_for_plt to use
when calling remove_eh_frame_for_plt, or recreating contents on the
fly (*) just to remove FDEs. In fact, FDE content matching is quite
unnecesary. FDEs added by a previous do_relax pass are those with
u_.from_linker.post_map set. So they can easily be recognised just by
looking at that flag. This patch keeps that part of the multiple FDE
changes.
In the end I went for just one FDE per stub group to describe the call
stubs. That's reasonably efficient for the common case of only
needing to describe the __tls_get_addr_opt call stub. We don't expect
to be making many calls using notoc stubs without pc-relative insns.
*) Which has it's own set of problems. The contents must be recreated
using the old stub layout, but .eh_frame size can affect stub
requirements so you need to temporarily keep the old .eh_frame size
when creating new stubs, then reset .eh_frame size before adding new
FDEs.
* ehframe.cc (Fde::operator==): Delete.
(Cie::remove_fde): Delete.
(Eh_frame::remove_ehframe_for_plt): Delete fde_data and fde_length
parameters. Remove all post-map plt FDEs.
* ehframe.h (Fde:post_map): Make const, add variant to compare plt.
(Fde::operator==): Delete.
(Cie::remove_fde): Implement here.
(Cie::last_fde): New accessor.
(Eh_frame::remove_ehframe_for_plt): Update prototype.
* layout.cc (Layout::remove_eh_frame_for_plt): Delete fde_data and
fde_length parameters.
* layout.h (Layout::remove_eh_frame_for_plt): Update prototype.
* powerpc.cc (Stub_table::tls_get_addr_opt_bctrl_): Delete.
(Stub_table::plt_fde_len_, plt_fde_, init_plt_fde): Delete.
(Stub_table::add_plt_call_entry): Don't set tls_get_addr_opt_bctrl_.
(eh_advance): New function.
(stub_sort): New function.
(Stub_table::add_eh_frame): Emit eh_frame for notoc plt calls and
branches as well as __tls_get_addr_opt plt call stub.
(Stub_table::remove_eh_frame): Update to suit.
2019-07-01 13:07:49 +08:00
|
|
|
while (pcie->fde_count() != 0)
|
|
|
|
{
|
|
|
|
const Fde* fde = pcie->last_fde();
|
|
|
|
if (!fde->post_map(plt))
|
|
|
|
break;
|
|
|
|
size_t length = fde->length();
|
|
|
|
this->final_data_size_ -= align_address(length + 8, this->addralign());
|
|
|
|
pcie->remove_fde();
|
|
|
|
}
|
[GOLD] PowerPC recreate eh_frame for stubs on each relax pass
There is a very small but non-zero probability that a stub group
contains stubs on one relax pass, but does not on the next. In that
case we would get an FDE covering a zero length address range.
(Actually, it's even worse. Alignment padding for stubs can mean the
address for the non-existent stubs is past the end of the original
section to which stubs are attached, and due to the way
do_plt_fde_location calculates the length we can get a negative
length.) Fixing this properly requires removing the FDE.
Also, I have been implementing the __tls_get_addr_opt support for
gold, and that stub needs something other than the default FDE. The
necessary FDE will depend on the offset to the __tls_get_addr_opt
stub, which of course can change during relaxation. That means at the
very least, rewriting the FDE on each pass, possibly changing the FDE
size. I think that is better done by completely recreating PLT
eh_frame FDEs.
* ehframe.cc (Fde::operator==): New.
(Cie::remove_fde, Eh_frame::remove_ehframe_for_plt): New.
* ehframe.h (Fde::operator==): Declare.
(Cie::remove_fde, Eh_frame::remove_ehframe_for_plt): Likewise.
* layout.cc (Layout::remove_eh_frame_for_plt): New.
* layout.h (Layout::remove_eh_frame_for_plt): Declare.
* powerpc.cc (Target_powerpc::do_relax): Remove old eh_frame FDEs.
(Stub_table::add_eh_frame): Delete eh_frame_added_ condition.
Don't add eh_frame for empty stub section.
(Stub_table::remove_eh_frame): New.
2017-08-01 12:38:53 +08:00
|
|
|
}
|
|
|
|
|
2007-11-09 15:00:15 +08:00
|
|
|
// Return the number of FDEs.
|
|
|
|
|
|
|
|
unsigned int
|
|
|
|
Eh_frame::fde_count() const
|
|
|
|
{
|
|
|
|
unsigned int ret = 0;
|
|
|
|
for (Unmergeable_cie_offsets::const_iterator p =
|
|
|
|
this->unmergeable_cie_offsets_.begin();
|
|
|
|
p != this->unmergeable_cie_offsets_.end();
|
|
|
|
++p)
|
2008-02-02 14:50:45 +08:00
|
|
|
ret += (*p)->fde_count();
|
2007-11-09 15:00:15 +08:00
|
|
|
for (Cie_offsets::const_iterator p = this->cie_offsets_.begin();
|
|
|
|
p != this->cie_offsets_.end();
|
|
|
|
++p)
|
2008-02-02 14:50:45 +08:00
|
|
|
ret += (*p)->fde_count();
|
2007-11-09 15:00:15 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the final data size.
|
|
|
|
|
|
|
|
void
|
2007-11-30 04:10:17 +08:00
|
|
|
Eh_frame::set_final_data_size()
|
2007-11-09 15:00:15 +08:00
|
|
|
{
|
2008-03-14 04:58:11 +08:00
|
|
|
// We can be called more than once if Layout::set_segment_offsets
|
|
|
|
// finds a better mapping. We don't want to add all the mappings
|
|
|
|
// again.
|
|
|
|
if (this->mappings_are_done_)
|
|
|
|
{
|
|
|
|
this->set_data_size(this->final_data_size_);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-07-03 00:39:41 +08:00
|
|
|
section_offset_type output_start = 0;
|
|
|
|
if (this->is_offset_valid())
|
|
|
|
output_start = this->offset() - this->output_section()->offset();
|
|
|
|
section_offset_type output_offset = output_start;
|
2007-11-09 15:00:15 +08:00
|
|
|
|
|
|
|
for (Unmergeable_cie_offsets::iterator p =
|
|
|
|
this->unmergeable_cie_offsets_.begin();
|
|
|
|
p != this->unmergeable_cie_offsets_.end();
|
|
|
|
++p)
|
2009-12-15 03:53:05 +08:00
|
|
|
output_offset = (*p)->set_output_offset(output_offset,
|
|
|
|
this->addralign(),
|
2015-03-05 07:10:18 +08:00
|
|
|
this);
|
2007-11-09 15:00:15 +08:00
|
|
|
|
|
|
|
for (Cie_offsets::iterator p = this->cie_offsets_.begin();
|
|
|
|
p != this->cie_offsets_.end();
|
|
|
|
++p)
|
2009-12-15 03:53:05 +08:00
|
|
|
output_offset = (*p)->set_output_offset(output_offset,
|
|
|
|
this->addralign(),
|
2015-03-05 07:10:18 +08:00
|
|
|
this);
|
2007-11-09 15:00:15 +08:00
|
|
|
|
2008-03-14 04:58:11 +08:00
|
|
|
this->mappings_are_done_ = true;
|
2014-07-03 00:39:41 +08:00
|
|
|
this->final_data_size_ = output_offset - output_start;
|
2008-03-14 04:58:11 +08:00
|
|
|
|
2009-12-15 03:53:05 +08:00
|
|
|
gold_assert((output_offset & (this->addralign() - 1)) == 0);
|
2014-07-03 00:39:41 +08:00
|
|
|
this->set_data_size(this->final_data_size_);
|
2007-11-09 15:00:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Return an output offset for an input offset.
|
|
|
|
|
|
|
|
bool
|
|
|
|
Eh_frame::do_output_offset(const Relobj* object, unsigned int shndx,
|
2009-12-15 03:53:05 +08:00
|
|
|
section_offset_type offset,
|
2007-12-18 08:48:04 +08:00
|
|
|
section_offset_type* poutput) const
|
2007-11-09 15:00:15 +08:00
|
|
|
{
|
2015-03-05 07:10:18 +08:00
|
|
|
return object->merge_output_offset(shndx, offset, poutput);
|
2007-12-22 05:19:45 +08:00
|
|
|
}
|
|
|
|
|
2007-11-09 15:00:15 +08:00
|
|
|
// Write the data to the output file.
|
|
|
|
|
|
|
|
void
|
|
|
|
Eh_frame::do_write(Output_file* of)
|
|
|
|
{
|
2009-12-15 03:53:05 +08:00
|
|
|
const off_t offset = this->offset();
|
2007-11-09 15:00:15 +08:00
|
|
|
const off_t oview_size = this->data_size();
|
2009-12-15 03:53:05 +08:00
|
|
|
unsigned char* const oview = of->get_output_view(offset, oview_size);
|
2007-11-09 15:00:15 +08:00
|
|
|
|
2008-02-28 08:18:24 +08:00
|
|
|
switch (parameters->size_and_endianness())
|
2007-11-09 15:00:15 +08:00
|
|
|
{
|
|
|
|
#ifdef HAVE_TARGET_32_LITTLE
|
2008-02-28 08:18:24 +08:00
|
|
|
case Parameters::TARGET_32_LITTLE:
|
|
|
|
this->do_sized_write<32, false>(oview);
|
|
|
|
break;
|
2007-11-09 15:00:15 +08:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_TARGET_32_BIG
|
2008-02-28 08:18:24 +08:00
|
|
|
case Parameters::TARGET_32_BIG:
|
|
|
|
this->do_sized_write<32, true>(oview);
|
|
|
|
break;
|
2007-11-09 15:00:15 +08:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_TARGET_64_LITTLE
|
2008-02-28 08:18:24 +08:00
|
|
|
case Parameters::TARGET_64_LITTLE:
|
|
|
|
this->do_sized_write<64, false>(oview);
|
|
|
|
break;
|
2007-11-09 15:00:15 +08:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_TARGET_64_BIG
|
2008-02-28 08:18:24 +08:00
|
|
|
case Parameters::TARGET_64_BIG:
|
|
|
|
this->do_sized_write<64, true>(oview);
|
|
|
|
break;
|
2007-11-09 15:00:15 +08:00
|
|
|
#endif
|
2008-02-28 08:18:24 +08:00
|
|
|
default:
|
|
|
|
gold_unreachable();
|
2007-11-09 15:00:15 +08:00
|
|
|
}
|
|
|
|
|
2009-12-15 03:53:05 +08:00
|
|
|
of->write_output_view(offset, oview_size, oview);
|
2007-11-09 15:00:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Write the data to the output file--template version.
|
|
|
|
|
|
|
|
template<int size, bool big_endian>
|
|
|
|
void
|
|
|
|
Eh_frame::do_sized_write(unsigned char* oview)
|
|
|
|
{
|
PR gold/12571
* options.h (class General_options): Add
--ld-generated-unwind-info.
* ehframe.cc (Fde::write): Add address parameter. Change all
callers. If associated with PLT, fill in address and size.
(Cie::set_output_offset): Only add merge mapping if there is an
object.
(Cie::write): Add address parameter. Change all callers.
(Eh_frame::add_ehframe_for_plt): New function.
* ehframe.h (class Fde): Update declarations. Move shndx_ and
input_offset_ fields into union u_, with new plt field.
(Fde::Fde): Adjust for new union field.
(Fde::Fde) [Output_data version]: New constructor.
(Fde::add_mapping): Only add merge mapping if there is an object.
(class Cie): Update declarations.
(class Eh_frame): Declare add_ehframe_for_plt.
* layout.cc (Layout::layout_eh_frame): Break out code into
make_eh_frame_section, and call it.
(Layout::make_eh_frame_section): New function.
(Layout::add_eh_frame_for_plt): New function.
* layout.h (class Layout): Update declarations.
* merge.cc (Merge_map::add_mapping): Add assertion.
* i386.cc: Include "dwarf.h".
(class Output_data_plt_i386): Make first_plt_entry,
dyn_first_plt_entry, exec_plt_entry, and dyn_plt_entry const. Add
plt_eh_frame_cie_size, plt_eh_frame_fde_size, plt_eh_frame_cie,
and plt_eh_frame_fde.
(Output_data_plt_i386::Output_data_plt_i386): Align to 16-byte
boundary. Call add_eh_frame_for_plt if appropriate.
* x86_64.cc: Include "dwarf.h".
(class Output_data_plt_x86_64): Align to 16-byte boundary. Make
first_plt_entry, plt_entry and tlsdesc_plt_entry const. Add
plt_eh_frame_cie_size, plt_eh_frame_fde_size, plt_eh_frame_cie,
and plt_eh_frame_fde.
(Output_data_plt_x86_64::init): Call add_eh_frame_for_plt if
appropriate.
2011-07-02 06:05:01 +08:00
|
|
|
uint64_t address = this->address();
|
2009-12-15 03:53:05 +08:00
|
|
|
unsigned int addralign = this->addralign();
|
2007-12-18 08:48:04 +08:00
|
|
|
section_offset_type o = 0;
|
2014-07-03 00:39:41 +08:00
|
|
|
const off_t output_offset = this->offset() - this->output_section()->offset();
|
* target.h (Target::plt_fde_location, do_plt_fde_location): Declare.
* target.cc (Target::do_plt_fde_location): New function.
* ehframe.h (class FDE): Add post_map field to u_.from_linker,
accessor function, and constructor param.
(struct Post_fde, Post_fdes): Declare.
(Cie::write): Add post_fdes param.
* ehframe.cc (Fde::write): Use plt_fde_location.
(struct Post_fde): Define.
(Cie::write): Stash FDEs added post merge mapping.
(Eh_frame::add_ehframe_for_plt): Assert no new CIEs after mapping.
Adjust Fde constructor call. Bump final_data_size_ for post map FDEs.
(Eh_frame::do_sized_write): Arrange to write post map FDES after
other FDEs.
* powerpc.cc (Target_powerpc::do_plt_fde_location): New function.
(Target_powerpc::has_glink): New function.
(Target_powerpc::do_relax): Add eh_frame info for stubs.
(struct Eh_cie, eh_frame_cie, glink_eh_frame_fde_64,
glink_eh_frame_fde_32, default_fde): New data.
(Stub_table::eh_frame_added_): New var.
(Stub_table::find_long_branch_entry, stub_address, stub_offset):
Make const.
(Stub_table::add_eh_frame): New function.
(Output_data_glink::add_eh_frame): New function.
(Target_powerpc::make_glink_section): Call add_eh_frame.
2013-02-28 07:11:56 +08:00
|
|
|
Post_fdes post_fdes;
|
2007-11-09 15:00:15 +08:00
|
|
|
for (Unmergeable_cie_offsets::iterator p =
|
|
|
|
this->unmergeable_cie_offsets_.begin();
|
|
|
|
p != this->unmergeable_cie_offsets_.end();
|
|
|
|
++p)
|
2014-07-03 00:39:41 +08:00
|
|
|
o = (*p)->write<size, big_endian>(oview, output_offset, o, address,
|
|
|
|
addralign, this->eh_frame_hdr_,
|
|
|
|
&post_fdes);
|
2007-11-09 15:00:15 +08:00
|
|
|
for (Cie_offsets::iterator p = this->cie_offsets_.begin();
|
|
|
|
p != this->cie_offsets_.end();
|
|
|
|
++p)
|
2014-07-03 00:39:41 +08:00
|
|
|
o = (*p)->write<size, big_endian>(oview, output_offset, o, address,
|
|
|
|
addralign, this->eh_frame_hdr_,
|
|
|
|
&post_fdes);
|
* target.h (Target::plt_fde_location, do_plt_fde_location): Declare.
* target.cc (Target::do_plt_fde_location): New function.
* ehframe.h (class FDE): Add post_map field to u_.from_linker,
accessor function, and constructor param.
(struct Post_fde, Post_fdes): Declare.
(Cie::write): Add post_fdes param.
* ehframe.cc (Fde::write): Use plt_fde_location.
(struct Post_fde): Define.
(Cie::write): Stash FDEs added post merge mapping.
(Eh_frame::add_ehframe_for_plt): Assert no new CIEs after mapping.
Adjust Fde constructor call. Bump final_data_size_ for post map FDEs.
(Eh_frame::do_sized_write): Arrange to write post map FDES after
other FDEs.
* powerpc.cc (Target_powerpc::do_plt_fde_location): New function.
(Target_powerpc::has_glink): New function.
(Target_powerpc::do_relax): Add eh_frame info for stubs.
(struct Eh_cie, eh_frame_cie, glink_eh_frame_fde_64,
glink_eh_frame_fde_32, default_fde): New data.
(Stub_table::eh_frame_added_): New var.
(Stub_table::find_long_branch_entry, stub_address, stub_offset):
Make const.
(Stub_table::add_eh_frame): New function.
(Output_data_glink::add_eh_frame): New function.
(Target_powerpc::make_glink_section): Call add_eh_frame.
2013-02-28 07:11:56 +08:00
|
|
|
for (Post_fdes::iterator p = post_fdes.begin();
|
|
|
|
p != post_fdes.end();
|
|
|
|
++p)
|
2014-07-03 00:39:41 +08:00
|
|
|
o = (*p).fde->write<size, big_endian>(oview, output_offset, o, address,
|
|
|
|
addralign, (*p).cie_offset,
|
2013-03-08 07:27:53 +08:00
|
|
|
(*p).fde_encoding,
|
|
|
|
this->eh_frame_hdr_);
|
2007-11-09 15:00:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef HAVE_TARGET_32_LITTLE
|
|
|
|
template
|
2015-03-10 01:10:29 +08:00
|
|
|
Eh_frame::Eh_frame_section_disposition
|
2007-11-09 15:00:15 +08:00
|
|
|
Eh_frame::add_ehframe_input_section<32, false>(
|
2011-05-25 05:41:10 +08:00
|
|
|
Sized_relobj_file<32, false>* object,
|
2007-11-09 15:00:15 +08:00
|
|
|
const unsigned char* symbols,
|
2007-12-18 08:48:04 +08:00
|
|
|
section_size_type symbols_size,
|
2007-11-09 15:00:15 +08:00
|
|
|
const unsigned char* symbol_names,
|
2007-12-18 08:48:04 +08:00
|
|
|
section_size_type symbol_names_size,
|
2007-11-09 15:00:15 +08:00
|
|
|
unsigned int shndx,
|
|
|
|
unsigned int reloc_shndx,
|
|
|
|
unsigned int reloc_type);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_TARGET_32_BIG
|
|
|
|
template
|
2015-03-10 01:10:29 +08:00
|
|
|
Eh_frame::Eh_frame_section_disposition
|
2007-11-09 15:00:15 +08:00
|
|
|
Eh_frame::add_ehframe_input_section<32, true>(
|
2011-05-25 05:41:10 +08:00
|
|
|
Sized_relobj_file<32, true>* object,
|
2007-11-09 15:00:15 +08:00
|
|
|
const unsigned char* symbols,
|
2007-12-18 08:48:04 +08:00
|
|
|
section_size_type symbols_size,
|
2007-11-09 15:00:15 +08:00
|
|
|
const unsigned char* symbol_names,
|
2007-12-18 08:48:04 +08:00
|
|
|
section_size_type symbol_names_size,
|
2007-11-09 15:00:15 +08:00
|
|
|
unsigned int shndx,
|
|
|
|
unsigned int reloc_shndx,
|
|
|
|
unsigned int reloc_type);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_TARGET_64_LITTLE
|
|
|
|
template
|
2015-03-10 01:10:29 +08:00
|
|
|
Eh_frame::Eh_frame_section_disposition
|
2007-11-09 15:00:15 +08:00
|
|
|
Eh_frame::add_ehframe_input_section<64, false>(
|
2011-05-25 05:41:10 +08:00
|
|
|
Sized_relobj_file<64, false>* object,
|
2007-11-09 15:00:15 +08:00
|
|
|
const unsigned char* symbols,
|
2007-12-18 08:48:04 +08:00
|
|
|
section_size_type symbols_size,
|
2007-11-09 15:00:15 +08:00
|
|
|
const unsigned char* symbol_names,
|
2007-12-18 08:48:04 +08:00
|
|
|
section_size_type symbol_names_size,
|
2007-11-09 15:00:15 +08:00
|
|
|
unsigned int shndx,
|
|
|
|
unsigned int reloc_shndx,
|
|
|
|
unsigned int reloc_type);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_TARGET_64_BIG
|
|
|
|
template
|
2015-03-10 01:10:29 +08:00
|
|
|
Eh_frame::Eh_frame_section_disposition
|
2007-11-09 15:00:15 +08:00
|
|
|
Eh_frame::add_ehframe_input_section<64, true>(
|
2011-05-25 05:41:10 +08:00
|
|
|
Sized_relobj_file<64, true>* object,
|
2007-11-09 15:00:15 +08:00
|
|
|
const unsigned char* symbols,
|
2007-12-18 08:48:04 +08:00
|
|
|
section_size_type symbols_size,
|
2007-11-09 15:00:15 +08:00
|
|
|
const unsigned char* symbol_names,
|
2007-12-18 08:48:04 +08:00
|
|
|
section_size_type symbol_names_size,
|
2007-11-09 15:00:15 +08:00
|
|
|
unsigned int shndx,
|
|
|
|
unsigned int reloc_shndx,
|
|
|
|
unsigned int reloc_type);
|
|
|
|
#endif
|
|
|
|
|
2007-09-26 13:44:38 +08:00
|
|
|
} // End namespace gold.
|