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.
This commit is contained in:
parent
a931db6a07
commit
07a6059735
@ -1,3 +1,42 @@
|
||||
2011-07-01 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
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-06-29 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
PR gold/12629
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// ehframe.cc -- handle exception frame sections for gold
|
||||
|
||||
// Copyright 2006, 2007, 2008, 2010 Free Software Foundation, Inc.
|
||||
// Copyright 2006, 2007, 2008, 2010, 2011 Free Software Foundation, Inc.
|
||||
// Written by Ian Lance Taylor <iant@google.com>.
|
||||
|
||||
// This file is part of gold.
|
||||
@ -321,14 +321,16 @@ Eh_frame_hdr::get_fde_addresses(Output_file* of,
|
||||
|
||||
// Write the FDE to OVIEW starting at OFFSET. CIE_OFFSET is the
|
||||
// offset of the CIE in OVIEW. FDE_ENCODING is the encoding, from the
|
||||
// CIE. ADDRALIGN is the required alignment. Record the FDE pc for
|
||||
// EH_FRAME_HDR. Return the new offset.
|
||||
// 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.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
section_offset_type
|
||||
Fde::write(unsigned char* oview, section_offset_type offset,
|
||||
unsigned int addralign, section_offset_type cie_offset,
|
||||
unsigned char fde_encoding, Eh_frame_hdr* eh_frame_hdr)
|
||||
uint64_t address, unsigned int addralign,
|
||||
section_offset_type cie_offset, unsigned char fde_encoding,
|
||||
Eh_frame_hdr* eh_frame_hdr)
|
||||
{
|
||||
gold_assert((offset & (addralign - 1)) == 0);
|
||||
|
||||
@ -355,6 +357,24 @@ Fde::write(unsigned char* oview, section_offset_type offset,
|
||||
// will later be applied to the FDE data.
|
||||
memcpy(oview + offset + 8, this->contents_.data(), length);
|
||||
|
||||
// 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);
|
||||
Output_data* plt = this->u_.from_linker.plt;
|
||||
uint64_t poffset = plt->address() - (address + offset + 8);
|
||||
int32_t spoffset = static_cast<int32_t>(poffset);
|
||||
off_t psize = plt->data_size();
|
||||
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);
|
||||
}
|
||||
|
||||
if (aligned_full_length > length + 8)
|
||||
memset(oview + offset + length + 8, 0, aligned_full_length - (length + 8));
|
||||
|
||||
@ -389,8 +409,12 @@ Cie::set_output_offset(section_offset_type output_offset,
|
||||
// Add 4 for length and 4 for zero CIE identifier tag.
|
||||
length += 8;
|
||||
|
||||
merge_map->add_mapping(this->object_, this->shndx_, this->input_offset_,
|
||||
length, output_offset);
|
||||
if (this->object_ != NULL)
|
||||
{
|
||||
// Add a mapping so that relocations are applied correctly.
|
||||
merge_map->add_mapping(this->object_, this->shndx_, this->input_offset_,
|
||||
length, output_offset);
|
||||
}
|
||||
|
||||
length = align_address(length, addralign);
|
||||
|
||||
@ -415,7 +439,8 @@ Cie::set_output_offset(section_offset_type output_offset,
|
||||
template<int size, bool big_endian>
|
||||
section_offset_type
|
||||
Cie::write(unsigned char* oview, section_offset_type offset,
|
||||
unsigned int addralign, Eh_frame_hdr* eh_frame_hdr)
|
||||
uint64_t address, unsigned int addralign,
|
||||
Eh_frame_hdr* eh_frame_hdr)
|
||||
{
|
||||
gold_assert((offset & (addralign - 1)) == 0);
|
||||
|
||||
@ -448,7 +473,7 @@ Cie::write(unsigned char* oview, section_offset_type offset,
|
||||
for (std::vector<Fde*>::const_iterator p = this->fdes_.begin();
|
||||
p != this->fdes_.end();
|
||||
++p)
|
||||
offset = (*p)->write<size, big_endian>(oview, offset, addralign,
|
||||
offset = (*p)->write<size, big_endian>(oview, offset, address, addralign,
|
||||
cie_offset, fde_encoding,
|
||||
eh_frame_hdr);
|
||||
|
||||
@ -994,6 +1019,29 @@ Eh_frame::read_fde(Sized_relobj_file<size, big_endian>* object,
|
||||
return true;
|
||||
}
|
||||
|
||||
// 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
|
||||
{
|
||||
pcie = new Cie(cie);
|
||||
this->cie_offsets_.insert(pcie);
|
||||
}
|
||||
|
||||
Fde* fde = new Fde(plt, fde_data, fde_length);
|
||||
pcie->add_fde(fde);
|
||||
}
|
||||
|
||||
// Return the number of FDEs.
|
||||
|
||||
unsigned int
|
||||
@ -1113,18 +1161,19 @@ template<int size, bool big_endian>
|
||||
void
|
||||
Eh_frame::do_sized_write(unsigned char* oview)
|
||||
{
|
||||
uint64_t address = this->address();
|
||||
unsigned int addralign = this->addralign();
|
||||
section_offset_type o = 0;
|
||||
for (Unmergeable_cie_offsets::iterator p =
|
||||
this->unmergeable_cie_offsets_.begin();
|
||||
p != this->unmergeable_cie_offsets_.end();
|
||||
++p)
|
||||
o = (*p)->write<size, big_endian>(oview, o, addralign,
|
||||
o = (*p)->write<size, big_endian>(oview, o, address, addralign,
|
||||
this->eh_frame_hdr_);
|
||||
for (Cie_offsets::iterator p = this->cie_offsets_.begin();
|
||||
p != this->cie_offsets_.end();
|
||||
++p)
|
||||
o = (*p)->write<size, big_endian>(oview, o, addralign,
|
||||
o = (*p)->write<size, big_endian>(oview, o, address, addralign,
|
||||
this->eh_frame_hdr_);
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// ehframe.h -- handle exception frame sections for gold -*- C++ -*-
|
||||
|
||||
// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
|
||||
// Copyright 2006, 2007, 2008, 2010, 2011 Free Software Foundation, Inc.
|
||||
// Written by Ian Lance Taylor <iant@google.com>.
|
||||
|
||||
// This file is part of gold.
|
||||
@ -45,10 +45,6 @@ class Eh_frame;
|
||||
// time and when a shared object is loaded, and the time required to
|
||||
// deregister the exception handlers when a shared object is unloaded.
|
||||
|
||||
// FIXME: gcc supports using storing a sorted lookup table for the
|
||||
// FDEs in the PT_GNU_EH_FRAME segment, but we do not yet generate
|
||||
// that.
|
||||
|
||||
class Eh_frame_hdr : public Output_section_data
|
||||
{
|
||||
public:
|
||||
@ -170,9 +166,18 @@ class Fde
|
||||
public:
|
||||
Fde(Relobj* object, unsigned int shndx, section_offset_type input_offset,
|
||||
const unsigned char* contents, size_t length)
|
||||
: object_(object), shndx_(shndx), input_offset_(input_offset),
|
||||
: object_(object),
|
||||
contents_(reinterpret_cast<const char*>(contents), length)
|
||||
{ }
|
||||
{
|
||||
this->u_.from_object.shndx = shndx;
|
||||
this->u_.from_object.input_offset = input_offset;
|
||||
}
|
||||
|
||||
// Create an FDE associated with a PLT.
|
||||
Fde(Output_data* plt, const unsigned char* contents, size_t length)
|
||||
: object_(NULL),
|
||||
contents_(reinterpret_cast<const char*>(contents), length)
|
||||
{ this->u_.from_linker.plt = plt; }
|
||||
|
||||
// Return the length of this FDE. Add 4 for the length and 4 for
|
||||
// the offset to the CIE.
|
||||
@ -180,32 +185,52 @@ class Fde
|
||||
length() const
|
||||
{ return this->contents_.length() + 8; }
|
||||
|
||||
// Add a mapping for this FDE to MERGE_MAP.
|
||||
// Add a mapping for this FDE to MERGE_MAP, so that relocations
|
||||
// against the FDE are applied to right part of the output file.
|
||||
void
|
||||
add_mapping(section_offset_type output_offset, Merge_map* merge_map) const
|
||||
{
|
||||
merge_map->add_mapping(this->object_, this->shndx_,
|
||||
this->input_offset_, this->length(),
|
||||
output_offset);
|
||||
if (this->object_ != NULL)
|
||||
merge_map->add_mapping(this->object_, this->u_.from_object.shndx,
|
||||
this->u_.from_object.input_offset, this->length(),
|
||||
output_offset);
|
||||
}
|
||||
|
||||
// Write the FDE to OVIEW starting at OFFSET. FDE_ENCODING is the
|
||||
// encoding, from the CIE. Round up the bytes to ADDRALIGN if
|
||||
// necessary. Record the FDE in EH_FRAME_HDR. Return the new
|
||||
// offset.
|
||||
// necessary. ADDRESS is the virtual address of OVIEW. Record the
|
||||
// FDE in EH_FRAME_HDR. Return the new offset.
|
||||
template<int size, bool big_endian>
|
||||
section_offset_type
|
||||
write(unsigned char* oview, section_offset_type offset,
|
||||
unsigned int addralign, section_offset_type cie_offset,
|
||||
unsigned char fde_encoding, Eh_frame_hdr* eh_frame_hdr);
|
||||
uint64_t address, unsigned int addralign,
|
||||
section_offset_type cie_offset, unsigned char fde_encoding,
|
||||
Eh_frame_hdr* eh_frame_hdr);
|
||||
|
||||
private:
|
||||
// The object in which this FDE was seen.
|
||||
// The object in which this FDE was seen. This will be NULL for a
|
||||
// linker generated FDE.
|
||||
Relobj* object_;
|
||||
// Input section index for this FDE.
|
||||
unsigned int shndx_;
|
||||
// Offset within the input section for this FDE.
|
||||
section_offset_type input_offset_;
|
||||
union
|
||||
{
|
||||
// These fields are used if the FDE is from an input object (the
|
||||
// object_ field is not NULL).
|
||||
struct
|
||||
{
|
||||
// Input section index for this FDE.
|
||||
unsigned int shndx;
|
||||
// Offset within the input section for this FDE.
|
||||
section_offset_type input_offset;
|
||||
} from_object;
|
||||
// This field is used if the FDE is generated by the linker (the
|
||||
// object_ field is NULL).
|
||||
struct
|
||||
{
|
||||
// The only linker generated FDEs are for PLT sections, and this
|
||||
// points to the PLT section.
|
||||
Output_data* plt;
|
||||
} from_linker;
|
||||
} u_;
|
||||
// FDE data.
|
||||
std::string contents_;
|
||||
};
|
||||
@ -261,10 +286,11 @@ class Cie
|
||||
|
||||
// Write the CIE to OVIEW starting at OFFSET. EH_FRAME_HDR is the
|
||||
// exception frame header for FDE recording. Round up the bytes to
|
||||
// ADDRALIGN. Return the new offset.
|
||||
// ADDRALIGN. ADDRESS is the virtual address of OVIEW. Return the
|
||||
// new offset.
|
||||
template<int size, bool big_endian>
|
||||
section_offset_type
|
||||
write(unsigned char* oview, section_offset_type offset,
|
||||
write(unsigned char* oview, section_offset_type offset, uint64_t address,
|
||||
unsigned int addralign, Eh_frame_hdr* eh_frame_hdr);
|
||||
|
||||
friend bool operator<(const Cie&, const Cie&);
|
||||
@ -274,11 +300,14 @@ class Cie
|
||||
// The class is not assignable.
|
||||
Cie& operator=(const Cie&);
|
||||
|
||||
// The object in which this CIE was first seen.
|
||||
// The object in which this CIE was first seen. This will be NULL
|
||||
// for a linker generated CIE.
|
||||
Relobj* object_;
|
||||
// Input section index for this CIE.
|
||||
// Input section index for this CIE. This will be 0 for a linker
|
||||
// generated CIE.
|
||||
unsigned int shndx_;
|
||||
// Offset within the input section for this CIE.
|
||||
// Offset within the input section for this CIE. This will be 0 for
|
||||
// a linker generated CIE.
|
||||
section_offset_type input_offset_;
|
||||
// The encoding of the FDE. This is a DW_EH_PE code.
|
||||
unsigned char fde_encoding_;
|
||||
@ -324,6 +353,15 @@ class Eh_frame : public Output_section_data
|
||||
unsigned int shndx, unsigned int reloc_shndx,
|
||||
unsigned int reloc_type);
|
||||
|
||||
// Add a CIE and an FDE for a PLT section, to permit unwinding
|
||||
// through a PLT. The FDE data should start with 8 bytes of zero,
|
||||
// which will be replaced by a 4 byte PC relative reference to the
|
||||
// address of PLT and a 4 byte size of PLT.
|
||||
void
|
||||
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);
|
||||
|
||||
// Return the number of FDEs.
|
||||
unsigned int
|
||||
fde_count() const;
|
||||
|
||||
78
gold/i386.cc
78
gold/i386.cc
@ -25,6 +25,7 @@
|
||||
#include <cstring>
|
||||
|
||||
#include "elfcpp.h"
|
||||
#include "dwarf.h"
|
||||
#include "parameters.h"
|
||||
#include "reloc.h"
|
||||
#include "i386.h"
|
||||
@ -101,16 +102,22 @@ class Output_data_plt_i386 : public Output_section_data
|
||||
static const int plt_entry_size = 16;
|
||||
|
||||
// The first entry in the PLT for an executable.
|
||||
static unsigned char exec_first_plt_entry[plt_entry_size];
|
||||
static const unsigned char exec_first_plt_entry[plt_entry_size];
|
||||
|
||||
// The first entry in the PLT for a shared object.
|
||||
static unsigned char dyn_first_plt_entry[plt_entry_size];
|
||||
static const unsigned char dyn_first_plt_entry[plt_entry_size];
|
||||
|
||||
// Other entries in the PLT for an executable.
|
||||
static unsigned char exec_plt_entry[plt_entry_size];
|
||||
static const unsigned char exec_plt_entry[plt_entry_size];
|
||||
|
||||
// Other entries in the PLT for a shared object.
|
||||
static unsigned char dyn_plt_entry[plt_entry_size];
|
||||
static const unsigned char dyn_plt_entry[plt_entry_size];
|
||||
|
||||
// The .eh_frame unwind information for the PLT.
|
||||
static const int plt_eh_frame_cie_size = 16;
|
||||
static const int plt_eh_frame_fde_size = 32;
|
||||
static const unsigned char plt_eh_frame_cie[plt_eh_frame_cie_size];
|
||||
static const unsigned char plt_eh_frame_fde[plt_eh_frame_fde_size];
|
||||
|
||||
// Set the final size.
|
||||
void
|
||||
@ -728,7 +735,7 @@ Target_i386::rel_dyn_section(Layout* layout)
|
||||
Output_data_plt_i386::Output_data_plt_i386(Symbol_table* symtab,
|
||||
Layout* layout,
|
||||
Output_data_space* got_plt)
|
||||
: Output_section_data(4), tls_desc_rel_(NULL), got_plt_(got_plt), count_(0),
|
||||
: Output_section_data(16), tls_desc_rel_(NULL), got_plt_(got_plt), count_(0),
|
||||
global_ifuncs_(), local_ifuncs_()
|
||||
{
|
||||
this->rel_ = new Reloc_section(false);
|
||||
@ -753,6 +760,11 @@ Output_data_plt_i386::Output_data_plt_i386(Symbol_table* symtab,
|
||||
elfcpp::STB_GLOBAL, elfcpp::STV_HIDDEN,
|
||||
0, true, true);
|
||||
}
|
||||
|
||||
// Add unwind information if requested.
|
||||
if (parameters->options().ld_generated_unwind_info())
|
||||
layout->add_eh_frame_for_plt(this, plt_eh_frame_cie, plt_eh_frame_cie_size,
|
||||
plt_eh_frame_fde, plt_eh_frame_fde_size);
|
||||
}
|
||||
|
||||
void
|
||||
@ -857,7 +869,7 @@ Output_data_plt_i386::rel_tls_desc(Layout* layout)
|
||||
|
||||
// The first entry in the PLT for an executable.
|
||||
|
||||
unsigned char Output_data_plt_i386::exec_first_plt_entry[plt_entry_size] =
|
||||
const unsigned char Output_data_plt_i386::exec_first_plt_entry[plt_entry_size] =
|
||||
{
|
||||
0xff, 0x35, // pushl contents of memory address
|
||||
0, 0, 0, 0, // replaced with address of .got + 4
|
||||
@ -868,7 +880,7 @@ unsigned char Output_data_plt_i386::exec_first_plt_entry[plt_entry_size] =
|
||||
|
||||
// The first entry in the PLT for a shared object.
|
||||
|
||||
unsigned char Output_data_plt_i386::dyn_first_plt_entry[plt_entry_size] =
|
||||
const unsigned char Output_data_plt_i386::dyn_first_plt_entry[plt_entry_size] =
|
||||
{
|
||||
0xff, 0xb3, 4, 0, 0, 0, // pushl 4(%ebx)
|
||||
0xff, 0xa3, 8, 0, 0, 0, // jmp *8(%ebx)
|
||||
@ -877,7 +889,7 @@ unsigned char Output_data_plt_i386::dyn_first_plt_entry[plt_entry_size] =
|
||||
|
||||
// Subsequent entries in the PLT for an executable.
|
||||
|
||||
unsigned char Output_data_plt_i386::exec_plt_entry[plt_entry_size] =
|
||||
const unsigned char Output_data_plt_i386::exec_plt_entry[plt_entry_size] =
|
||||
{
|
||||
0xff, 0x25, // jmp indirect
|
||||
0, 0, 0, 0, // replaced with address of symbol in .got
|
||||
@ -889,7 +901,7 @@ unsigned char Output_data_plt_i386::exec_plt_entry[plt_entry_size] =
|
||||
|
||||
// Subsequent entries in the PLT for a shared object.
|
||||
|
||||
unsigned char Output_data_plt_i386::dyn_plt_entry[plt_entry_size] =
|
||||
const unsigned char Output_data_plt_i386::dyn_plt_entry[plt_entry_size] =
|
||||
{
|
||||
0xff, 0xa3, // jmp *offset(%ebx)
|
||||
0, 0, 0, 0, // replaced with offset of symbol in .got
|
||||
@ -899,6 +911,54 @@ unsigned char Output_data_plt_i386::dyn_plt_entry[plt_entry_size] =
|
||||
0, 0, 0, 0 // replaced with offset to start of .plt
|
||||
};
|
||||
|
||||
// The .eh_frame unwind information for the PLT.
|
||||
|
||||
const unsigned char
|
||||
Output_data_plt_i386::plt_eh_frame_cie[plt_eh_frame_cie_size] =
|
||||
{
|
||||
1, // CIE version.
|
||||
'z', // Augmentation: augmentation size included.
|
||||
'R', // Augmentation: FDE encoding included.
|
||||
'\0', // End of augmentation string.
|
||||
1, // Code alignment factor.
|
||||
0x7c, // Data alignment factor.
|
||||
8, // Return address column.
|
||||
1, // Augmentation size.
|
||||
(elfcpp::DW_EH_PE_pcrel // FDE encoding.
|
||||
| elfcpp::DW_EH_PE_sdata4),
|
||||
elfcpp::DW_CFA_def_cfa, 4, 4, // DW_CFA_def_cfa: r4 (esp) ofs 4.
|
||||
elfcpp::DW_CFA_offset + 8, 1, // DW_CFA_offset: r8 (eip) at cfa-4.
|
||||
elfcpp::DW_CFA_nop, // Align to 16 bytes.
|
||||
elfcpp::DW_CFA_nop
|
||||
};
|
||||
|
||||
const unsigned char
|
||||
Output_data_plt_i386::plt_eh_frame_fde[plt_eh_frame_fde_size] =
|
||||
{
|
||||
0, 0, 0, 0, // Replaced with offset to .plt.
|
||||
0, 0, 0, 0, // Replaced with size of .plt.
|
||||
0, // Augmentation size.
|
||||
elfcpp::DW_CFA_def_cfa_offset, 8, // DW_CFA_def_cfa_offset: 8.
|
||||
elfcpp::DW_CFA_advance_loc + 6, // Advance 6 to __PLT__ + 6.
|
||||
elfcpp::DW_CFA_def_cfa_offset, 12, // DW_CFA_def_cfa_offset: 12.
|
||||
elfcpp::DW_CFA_advance_loc + 10, // Advance 10 to __PLT__ + 16.
|
||||
elfcpp::DW_CFA_def_cfa_expression, // DW_CFA_def_cfa_expression.
|
||||
11, // Block length.
|
||||
elfcpp::DW_OP_breg4, 4, // Push %esp + 4.
|
||||
elfcpp::DW_OP_breg8, 0, // Push %eip.
|
||||
elfcpp::DW_OP_lit15, // Push 0xf.
|
||||
elfcpp::DW_OP_and, // & (%eip & 0xf).
|
||||
elfcpp::DW_OP_lit11, // Push 0xb.
|
||||
elfcpp::DW_OP_ge, // >= ((%eip & 0xf) >= 0xb)
|
||||
elfcpp::DW_OP_lit2, // Push 2.
|
||||
elfcpp::DW_OP_shl, // << (((%eip & 0xf) >= 0xb) << 2)
|
||||
elfcpp::DW_OP_plus, // + ((((%eip&0xf)>=0xb)<<2)+%esp+8
|
||||
elfcpp::DW_CFA_nop, // Align to 32 bytes.
|
||||
elfcpp::DW_CFA_nop,
|
||||
elfcpp::DW_CFA_nop,
|
||||
elfcpp::DW_CFA_nop
|
||||
};
|
||||
|
||||
// Write out the PLT. This uses the hand-coded instructions above,
|
||||
// and adjusts them as needed. This is all specified by the i386 ELF
|
||||
// Processor Supplement.
|
||||
|
||||
143
gold/layout.cc
143
gold/layout.cc
@ -1136,8 +1136,73 @@ Layout::layout_eh_frame(Sized_relobj_file<size, big_endian>* object,
|
||||
|| shdr.get_sh_type() == elfcpp::SHT_X86_64_UNWIND);
|
||||
gold_assert((shdr.get_sh_flags() & elfcpp::SHF_ALLOC) != 0);
|
||||
|
||||
const char* const name = ".eh_frame";
|
||||
Output_section* os = this->choose_output_section(object, name,
|
||||
Output_section* os = this->make_eh_frame_section(object);
|
||||
if (os == NULL)
|
||||
return NULL;
|
||||
|
||||
gold_assert(this->eh_frame_section_ == os);
|
||||
|
||||
elfcpp::Elf_Xword orig_flags = os->flags();
|
||||
|
||||
if (!parameters->incremental()
|
||||
&& this->eh_frame_data_->add_ehframe_input_section(object,
|
||||
symbols,
|
||||
symbols_size,
|
||||
symbol_names,
|
||||
symbol_names_size,
|
||||
shndx,
|
||||
reloc_shndx,
|
||||
reloc_type))
|
||||
{
|
||||
os->update_flags_for_input_section(shdr.get_sh_flags());
|
||||
|
||||
// A writable .eh_frame section is a RELRO section.
|
||||
if ((orig_flags & (elfcpp::SHF_WRITE | elfcpp::SHF_EXECINSTR))
|
||||
!= (os->flags() & (elfcpp::SHF_WRITE | elfcpp::SHF_EXECINSTR)))
|
||||
{
|
||||
os->set_is_relro();
|
||||
os->set_order(ORDER_RELRO);
|
||||
}
|
||||
|
||||
// We found a .eh_frame section we are going to optimize, so now
|
||||
// we can add the set of optimized sections to the output
|
||||
// section. We need to postpone adding this until we've found a
|
||||
// section we can optimize so that the .eh_frame section in
|
||||
// crtbegin.o winds up at the start of the output section.
|
||||
if (!this->added_eh_frame_data_)
|
||||
{
|
||||
os->add_output_section_data(this->eh_frame_data_);
|
||||
this->added_eh_frame_data_ = true;
|
||||
}
|
||||
*off = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We couldn't handle this .eh_frame section for some reason.
|
||||
// Add it as a normal section.
|
||||
bool saw_sections_clause = this->script_options_->saw_sections_clause();
|
||||
*off = os->add_input_section(this, object, shndx, ".eh_frame", shdr,
|
||||
reloc_shndx, saw_sections_clause);
|
||||
this->have_added_input_section_ = true;
|
||||
|
||||
if ((orig_flags & (elfcpp::SHF_WRITE | elfcpp::SHF_EXECINSTR))
|
||||
!= (os->flags() & (elfcpp::SHF_WRITE | elfcpp::SHF_EXECINSTR)))
|
||||
os->set_order(this->default_section_order(os, false));
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
// Create and return the magic .eh_frame section. Create
|
||||
// .eh_frame_hdr also if appropriate. OBJECT is the object with the
|
||||
// input .eh_frame section; it may be NULL.
|
||||
|
||||
Output_section*
|
||||
Layout::make_eh_frame_section(const Relobj* object)
|
||||
{
|
||||
// FIXME: On x86_64, this could use SHT_X86_64_UNWIND rather than
|
||||
// SHT_PROGBITS.
|
||||
Output_section* os = this->choose_output_section(object, ".eh_frame",
|
||||
elfcpp::SHT_PROGBITS,
|
||||
elfcpp::SHF_ALLOC, false,
|
||||
ORDER_EHFRAME, false);
|
||||
@ -1181,59 +1246,33 @@ Layout::layout_eh_frame(Sized_relobj_file<size, big_endian>* object,
|
||||
}
|
||||
}
|
||||
|
||||
gold_assert(this->eh_frame_section_ == os);
|
||||
|
||||
elfcpp::Elf_Xword orig_flags = os->flags();
|
||||
|
||||
if (!parameters->incremental()
|
||||
&& this->eh_frame_data_->add_ehframe_input_section(object,
|
||||
symbols,
|
||||
symbols_size,
|
||||
symbol_names,
|
||||
symbol_names_size,
|
||||
shndx,
|
||||
reloc_shndx,
|
||||
reloc_type))
|
||||
{
|
||||
os->update_flags_for_input_section(shdr.get_sh_flags());
|
||||
|
||||
// A writable .eh_frame section is a RELRO section.
|
||||
if ((orig_flags & (elfcpp::SHF_WRITE | elfcpp::SHF_EXECINSTR))
|
||||
!= (os->flags() & (elfcpp::SHF_WRITE | elfcpp::SHF_EXECINSTR)))
|
||||
{
|
||||
os->set_is_relro();
|
||||
os->set_order(ORDER_RELRO);
|
||||
}
|
||||
|
||||
// We found a .eh_frame section we are going to optimize, so now
|
||||
// we can add the set of optimized sections to the output
|
||||
// section. We need to postpone adding this until we've found a
|
||||
// section we can optimize so that the .eh_frame section in
|
||||
// crtbegin.o winds up at the start of the output section.
|
||||
if (!this->added_eh_frame_data_)
|
||||
{
|
||||
os->add_output_section_data(this->eh_frame_data_);
|
||||
this->added_eh_frame_data_ = true;
|
||||
}
|
||||
*off = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We couldn't handle this .eh_frame section for some reason.
|
||||
// Add it as a normal section.
|
||||
bool saw_sections_clause = this->script_options_->saw_sections_clause();
|
||||
*off = os->add_input_section(this, object, shndx, name, shdr, reloc_shndx,
|
||||
saw_sections_clause);
|
||||
this->have_added_input_section_ = true;
|
||||
|
||||
if ((orig_flags & (elfcpp::SHF_WRITE | elfcpp::SHF_EXECINSTR))
|
||||
!= (os->flags() & (elfcpp::SHF_WRITE | elfcpp::SHF_EXECINSTR)))
|
||||
os->set_order(this->default_section_order(os, false));
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
// Add an exception frame for a PLT. This is called from target code.
|
||||
|
||||
void
|
||||
Layout::add_eh_frame_for_plt(Output_data* plt, const unsigned char* cie_data,
|
||||
size_t cie_length, const unsigned char* fde_data,
|
||||
size_t fde_length)
|
||||
{
|
||||
if (parameters->incremental())
|
||||
{
|
||||
// FIXME: Maybe this could work some day....
|
||||
return;
|
||||
}
|
||||
Output_section* os = this->make_eh_frame_section(NULL);
|
||||
if (os == NULL)
|
||||
return;
|
||||
this->eh_frame_data_->add_ehframe_for_plt(plt, cie_data, cie_length,
|
||||
fde_data, fde_length);
|
||||
if (!this->added_eh_frame_data_)
|
||||
{
|
||||
os->add_output_section_data(this->eh_frame_data_);
|
||||
this->added_eh_frame_data_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Add POSD to an output section using NAME, TYPE, and FLAGS. Return
|
||||
// the output section.
|
||||
|
||||
|
||||
@ -549,6 +549,14 @@ class Layout
|
||||
unsigned int reloc_shndx, unsigned int reloc_type,
|
||||
off_t* offset);
|
||||
|
||||
// Add .eh_frame information for a PLT. The FDE must start with a
|
||||
// 4-byte PC-relative reference to the start of the PLT, followed by
|
||||
// a 4-byte size of PLT.
|
||||
void
|
||||
add_eh_frame_for_plt(Output_data* plt, const unsigned char* cie_data,
|
||||
size_t cie_length, const unsigned char* fde_data,
|
||||
size_t fde_length);
|
||||
|
||||
// Handle a GNU stack note. This is called once per input object
|
||||
// file. SEEN_GNU_STACK is true if the object file has a
|
||||
// .note.GNU-stack section. GNU_STACK_FLAGS is the section flags
|
||||
@ -1018,6 +1026,10 @@ class Layout
|
||||
void
|
||||
attach_allocated_section_to_segment(Output_section*);
|
||||
|
||||
// Make the .eh_frame section.
|
||||
Output_section*
|
||||
make_eh_frame_section(const Relobj*);
|
||||
|
||||
// Set the final file offsets of all the segments.
|
||||
off_t
|
||||
set_segment_offsets(const Target*, Output_segment*, unsigned int* pshndx);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// merge.cc -- handle section merging for gold
|
||||
|
||||
// Copyright 2006, 2007, 2008, 2010 Free Software Foundation, Inc.
|
||||
// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
|
||||
// Written by Ian Lance Taylor <iant@google.com>.
|
||||
|
||||
// This file is part of gold.
|
||||
@ -242,6 +242,7 @@ Merge_map::add_mapping(Relobj* object, unsigned int shndx,
|
||||
section_offset_type offset, section_size_type length,
|
||||
section_offset_type output_offset)
|
||||
{
|
||||
gold_assert(object != NULL);
|
||||
Object_merge_map* object_merge_map = object->merge_map();
|
||||
if (object_merge_map == NULL)
|
||||
{
|
||||
|
||||
@ -820,6 +820,10 @@ class General_options
|
||||
N_("Keep files mapped across passes (default)"),
|
||||
N_("Release mapped files after each pass"));
|
||||
|
||||
DEFINE_bool(ld_generated_unwind_info, options::TWO_DASHES, '\0', true,
|
||||
N_("Generate unwind information for PLT (default)"),
|
||||
N_("Do not generate unwind information for PLT"));
|
||||
|
||||
DEFINE_special(library, options::TWO_DASHES, 'l',
|
||||
N_("Search for library LIBNAME"), N_("LIBNAME"));
|
||||
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
#include <cstring>
|
||||
|
||||
#include "elfcpp.h"
|
||||
#include "dwarf.h"
|
||||
#include "parameters.h"
|
||||
#include "reloc.h"
|
||||
#include "x86_64.h"
|
||||
@ -56,7 +57,7 @@ class Output_data_plt_x86_64 : public Output_section_data
|
||||
Output_data_plt_x86_64(Symbol_table* symtab, Layout* layout,
|
||||
Output_data_got<64, false>* got,
|
||||
Output_data_space* got_plt)
|
||||
: Output_section_data(8), tlsdesc_rel_(NULL), got_(got), got_plt_(got_plt),
|
||||
: Output_section_data(16), tlsdesc_rel_(NULL), got_(got), got_plt_(got_plt),
|
||||
count_(0), tlsdesc_got_offset_(-1U), free_list_()
|
||||
{ this->init(symtab, layout); }
|
||||
|
||||
@ -64,7 +65,7 @@ class Output_data_plt_x86_64 : public Output_section_data
|
||||
Output_data_got<64, false>* got,
|
||||
Output_data_space* got_plt,
|
||||
unsigned int plt_count)
|
||||
: Output_section_data((plt_count + 1) * plt_entry_size, 8, false),
|
||||
: Output_section_data((plt_count + 1) * plt_entry_size, 16, false),
|
||||
tlsdesc_rel_(NULL), got_(got), got_plt_(got_plt),
|
||||
count_(plt_count), tlsdesc_got_offset_(-1U), free_list_()
|
||||
{
|
||||
@ -160,13 +161,19 @@ class Output_data_plt_x86_64 : public Output_section_data
|
||||
// The first entry in the PLT.
|
||||
// From the AMD64 ABI: "Unlike Intel386 ABI, this ABI uses the same
|
||||
// procedure linkage table for both programs and shared objects."
|
||||
static unsigned char first_plt_entry[plt_entry_size];
|
||||
static const unsigned char first_plt_entry[plt_entry_size];
|
||||
|
||||
// Other entries in the PLT for an executable.
|
||||
static unsigned char plt_entry[plt_entry_size];
|
||||
static const unsigned char plt_entry[plt_entry_size];
|
||||
|
||||
// The reserved TLSDESC entry in the PLT for an executable.
|
||||
static unsigned char tlsdesc_plt_entry[plt_entry_size];
|
||||
static const unsigned char tlsdesc_plt_entry[plt_entry_size];
|
||||
|
||||
// The .eh_frame unwind information for the PLT.
|
||||
static const int plt_eh_frame_cie_size = 16;
|
||||
static const int plt_eh_frame_fde_size = 32;
|
||||
static const unsigned char plt_eh_frame_cie[plt_eh_frame_cie_size];
|
||||
static const unsigned char plt_eh_frame_fde[plt_eh_frame_fde_size];
|
||||
|
||||
// Set the final size.
|
||||
void
|
||||
@ -871,6 +878,11 @@ Output_data_plt_x86_64::init(Symbol_table* symtab, Layout* layout)
|
||||
elfcpp::STB_GLOBAL, elfcpp::STV_HIDDEN,
|
||||
0, true, true);
|
||||
}
|
||||
|
||||
// Add unwind information if requested.
|
||||
if (parameters->options().ld_generated_unwind_info())
|
||||
layout->add_eh_frame_for_plt(this, plt_eh_frame_cie, plt_eh_frame_cie_size,
|
||||
plt_eh_frame_fde, plt_eh_frame_fde_size);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1004,7 +1016,7 @@ Output_data_plt_x86_64::set_final_data_size()
|
||||
|
||||
// The first entry in the PLT for an executable.
|
||||
|
||||
unsigned char Output_data_plt_x86_64::first_plt_entry[plt_entry_size] =
|
||||
const unsigned char Output_data_plt_x86_64::first_plt_entry[plt_entry_size] =
|
||||
{
|
||||
// From AMD64 ABI Draft 0.98, page 76
|
||||
0xff, 0x35, // pushq contents of memory address
|
||||
@ -1016,7 +1028,7 @@ unsigned char Output_data_plt_x86_64::first_plt_entry[plt_entry_size] =
|
||||
|
||||
// Subsequent entries in the PLT for an executable.
|
||||
|
||||
unsigned char Output_data_plt_x86_64::plt_entry[plt_entry_size] =
|
||||
const unsigned char Output_data_plt_x86_64::plt_entry[plt_entry_size] =
|
||||
{
|
||||
// From AMD64 ABI Draft 0.98, page 76
|
||||
0xff, 0x25, // jmpq indirect
|
||||
@ -1029,7 +1041,7 @@ unsigned char Output_data_plt_x86_64::plt_entry[plt_entry_size] =
|
||||
|
||||
// The reserved TLSDESC entry in the PLT for an executable.
|
||||
|
||||
unsigned char Output_data_plt_x86_64::tlsdesc_plt_entry[plt_entry_size] =
|
||||
const unsigned char Output_data_plt_x86_64::tlsdesc_plt_entry[plt_entry_size] =
|
||||
{
|
||||
// From Alexandre Oliva, "Thread-Local Storage Descriptors for IA32
|
||||
// and AMD64/EM64T", Version 0.9.4 (2005-10-10).
|
||||
@ -1041,6 +1053,54 @@ unsigned char Output_data_plt_x86_64::tlsdesc_plt_entry[plt_entry_size] =
|
||||
0x40, 0
|
||||
};
|
||||
|
||||
// The .eh_frame unwind information for the PLT.
|
||||
|
||||
const unsigned char
|
||||
Output_data_plt_x86_64::plt_eh_frame_cie[plt_eh_frame_cie_size] =
|
||||
{
|
||||
1, // CIE version.
|
||||
'z', // Augmentation: augmentation size included.
|
||||
'R', // Augmentation: FDE encoding included.
|
||||
'\0', // End of augmentation string.
|
||||
1, // Code alignment factor.
|
||||
0x78, // Data alignment factor.
|
||||
16, // Return address column.
|
||||
1, // Augmentation size.
|
||||
(elfcpp::DW_EH_PE_pcrel // FDE encoding.
|
||||
| elfcpp::DW_EH_PE_sdata4),
|
||||
elfcpp::DW_CFA_def_cfa, 7, 8, // DW_CFA_def_cfa: r7 (rsp) ofs 8.
|
||||
elfcpp::DW_CFA_offset + 16, 1,// DW_CFA_offset: r16 (rip) at cfa-8.
|
||||
elfcpp::DW_CFA_nop, // Align to 16 bytes.
|
||||
elfcpp::DW_CFA_nop
|
||||
};
|
||||
|
||||
const unsigned char
|
||||
Output_data_plt_x86_64::plt_eh_frame_fde[plt_eh_frame_fde_size] =
|
||||
{
|
||||
0, 0, 0, 0, // Replaced with offset to .plt.
|
||||
0, 0, 0, 0, // Replaced with size of .plt.
|
||||
0, // Augmentation size.
|
||||
elfcpp::DW_CFA_def_cfa_offset, 16, // DW_CFA_def_cfa_offset: 16.
|
||||
elfcpp::DW_CFA_advance_loc + 6, // Advance 6 to __PLT__ + 6.
|
||||
elfcpp::DW_CFA_def_cfa_offset, 24, // DW_CFA_def_cfa_offset: 24.
|
||||
elfcpp::DW_CFA_advance_loc + 10, // Advance 10 to __PLT__ + 16.
|
||||
elfcpp::DW_CFA_def_cfa_expression, // DW_CFA_def_cfa_expression.
|
||||
11, // Block length.
|
||||
elfcpp::DW_OP_breg7, 8, // Push %rsp + 8.
|
||||
elfcpp::DW_OP_breg16, 0, // Push %rip.
|
||||
elfcpp::DW_OP_lit15, // Push 0xf.
|
||||
elfcpp::DW_OP_and, // & (%rip & 0xf).
|
||||
elfcpp::DW_OP_lit11, // Push 0xb.
|
||||
elfcpp::DW_OP_ge, // >= ((%rip & 0xf) >= 0xb)
|
||||
elfcpp::DW_OP_lit3, // Push 3.
|
||||
elfcpp::DW_OP_shl, // << (((%rip & 0xf) >= 0xb) << 3)
|
||||
elfcpp::DW_OP_plus, // + ((((%rip&0xf)>=0xb)<<3)+%rsp+8
|
||||
elfcpp::DW_CFA_nop, // Align to 32 bytes.
|
||||
elfcpp::DW_CFA_nop,
|
||||
elfcpp::DW_CFA_nop,
|
||||
elfcpp::DW_CFA_nop
|
||||
};
|
||||
|
||||
// Write out the PLT. This uses the hand-coded instructions above,
|
||||
// and adjusts them as needed. This is specified by the AMD64 ABI.
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user