aboutsummaryrefslogtreecommitdiff
path: root/gold/i386.cc
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@airs.com>2011-07-01 22:05:01 +0000
committerIan Lance Taylor <ian@airs.com>2011-07-01 22:05:01 +0000
commit07a60597350488f098508ee67717d549a8a0b579 (patch)
tree2476e48897011f57f41615892bdffda825fde6b2 /gold/i386.cc
parenta931db6a07ac9ae2fec6c31c6d037716050292c5 (diff)
downloadgdb-07a60597350488f098508ee67717d549a8a0b579.zip
gdb-07a60597350488f098508ee67717d549a8a0b579.tar.gz
gdb-07a60597350488f098508ee67717d549a8a0b579.tar.bz2
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.
Diffstat (limited to 'gold/i386.cc')
-rw-r--r--gold/i386.cc78
1 files changed, 69 insertions, 9 deletions
diff --git a/gold/i386.cc b/gold/i386.cc
index beec4a8..636dfbb 100644
--- a/gold/i386.cc
+++ b/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.