diff options
Diffstat (limited to 'gold/x86_64.cc')
-rw-r--r-- | gold/x86_64.cc | 76 |
1 files changed, 68 insertions, 8 deletions
diff --git a/gold/x86_64.cc b/gold/x86_64.cc index de39cb42887..12a5467f3f5 100644 --- a/gold/x86_64.cc +++ b/gold/x86_64.cc @@ -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. |