X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gold%2Flayout.cc;h=f5a1f671e059f6beb485f342dc331fbbdd9bd393;hb=4117d76827b3768e9da6ef52f52a59c5ae92bed3;hp=d45970dab005fc96f318b6ef755a034f563d9af8;hpb=a0fa0c079821efa6780ed2f612b0a0a021c5e082;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/layout.cc b/gold/layout.cc index d45970dab0..f5a1f671e0 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -31,6 +31,8 @@ #include "output.h" #include "symtab.h" #include "dynobj.h" +#include "ehframe.h" +#include "compressed_output.h" #include "layout.h" namespace gold @@ -64,16 +66,20 @@ Layout::Layout(const General_options& options) : options_(options), namepool_(), sympool_(), dynpool_(), signatures_(), section_name_map_(), segment_list_(), section_list_(), unattached_section_list_(), special_output_list_(), - tls_segment_(NULL), symtab_section_(NULL), - dynsym_section_(NULL), dynamic_section_(NULL), dynamic_data_(NULL) + section_headers_(NULL), tls_segment_(NULL), symtab_section_(NULL), + dynsym_section_(NULL), dynamic_section_(NULL), dynamic_data_(NULL), + eh_frame_section_(NULL), output_file_size_(-1), + input_requires_executable_stack_(false), + input_with_gnu_stack_note_(false), + input_without_gnu_stack_note_(false) { // Make space for more than enough segments for a typical file. // This is just for efficiency--it's OK if we wind up needing more. this->segment_list_.reserve(12); - // We expect three unattached Output_data objects: the file header, - // the segment headers, and the section headers. - this->special_output_list_.reserve(3); + // We expect two unattached Output_data objects: the file header and + // the segment headers. + this->special_output_list_.reserve(2); } // Hash a key we use to look up an output section mapping. @@ -84,11 +90,46 @@ Layout::Hash_key::operator()(const Layout::Key& k) const return k.first + k.second.first + k.second.second; } +// Return whether PREFIX is a prefix of STR. + +static inline bool +is_prefix_of(const char* prefix, const char* str) +{ + return strncmp(prefix, str, strlen(prefix)) == 0; +} + +// Returns whether the given section is in the list of +// debug-sections-used-by-some-version-of-gdb. Currently, +// we've checked versions of gdb up to and including 6.7.1. + +static const char* gdb_sections[] = +{ ".debug_abbrev", + // ".debug_aranges", // not used by gdb as of 6.7.1 + ".debug_frame", + ".debug_info", + ".debug_line", + ".debug_loc", + ".debug_macinfo", + // ".debug_pubnames", // not used by gdb as of 6.7.1 + ".debug_ranges", + ".debug_str", +}; + +static inline bool +is_gdb_debug_section(const char* str) +{ + // We can do this faster: binary search or a hashtable. But why bother? + for (size_t i = 0; i < sizeof(gdb_sections)/sizeof(*gdb_sections); ++i) + if (strcmp(str, gdb_sections[i]) == 0) + return true; + return false; +} + // Whether to include this section in the link. template bool -Layout::include_section(Object*, const char*, +Layout::include_section(Sized_relobj*, const char* name, const elfcpp::Shdr& shdr) { // Some section types are never linked. Some are only linked when @@ -109,8 +150,28 @@ Layout::include_section(Object*, const char*, case elfcpp::SHT_GROUP: return parameters->output_is_object(); + case elfcpp::SHT_PROGBITS: + if (parameters->strip_debug() + && (shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0) + { + // Debugging sections can only be recognized by name. + if (is_prefix_of(".debug", name) + || is_prefix_of(".gnu.linkonce.wi.", name) + || is_prefix_of(".line", name) + || is_prefix_of(".stab", name)) + return false; + } + if (parameters->strip_debug_gdb() + && (shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0) + { + // Debugging sections can only be recognized by name. + if (is_prefix_of(".debug", name) + && !is_gdb_debug_section(name)) + return false; + } + return true; + default: - // FIXME: Handle stripping debug sections here. return true; } } @@ -177,13 +238,20 @@ Layout::get_output_section(const char* name, Stringpool::Key name_key, } // Return the output section to use for input section SHNDX, with name -// NAME, with header HEADER, from object OBJECT. Set *OFF to the -// offset of this input section without the output section. +// NAME, with header HEADER, from object OBJECT. RELOC_SHNDX is the +// index of a relocation section which applies to this section, or 0 +// if none, or -1U if more than one. RELOC_TYPE is the type of the +// relocation section if there is one. Set *OFF to the offset of this +// input section without the output section. Return NULL if the +// section should be discarded. Set *OFF to -1 if the section +// contents should not be written directly to the output file, but +// will instead receive special handling. template Output_section* -Layout::layout(Relobj* object, unsigned int shndx, const char* name, - const elfcpp::Shdr& shdr, off_t* off) +Layout::layout(Sized_relobj* object, unsigned int shndx, + const char* name, const elfcpp::Shdr& shdr, + unsigned int reloc_shndx, unsigned int, off_t* off) { if (!this->include_section(object, name, shdr)) return NULL; @@ -198,7 +266,7 @@ Layout::layout(Relobj* object, unsigned int shndx, const char* name, // Canonicalize the section name. Stringpool::Key name_key; - name = this->namepool_.add(name, len, &name_key); + name = this->namepool_.add_prefix(name, len, &name_key); // Find the output section. The output section is selected based on // the section name, type, and flags. @@ -208,7 +276,85 @@ Layout::layout(Relobj* object, unsigned int shndx, const char* name, // FIXME: Handle SHF_LINK_ORDER somewhere. - *off = os->add_input_section(object, shndx, name, shdr); + *off = os->add_input_section(object, shndx, name, shdr, reloc_shndx); + + return os; +} + +// Special GNU handling of sections name .eh_frame. They will +// normally hold exception frame data as defined by the C++ ABI +// (http://codesourcery.com/cxx-abi/). + +template +Output_section* +Layout::layout_eh_frame(Sized_relobj* object, + const unsigned char* symbols, + off_t symbols_size, + const unsigned char* symbol_names, + off_t symbol_names_size, + unsigned int shndx, + const elfcpp::Shdr& shdr, + unsigned int reloc_shndx, unsigned int reloc_type, + off_t* off) +{ + gold_assert(shdr.get_sh_type() == elfcpp::SHT_PROGBITS); + gold_assert(shdr.get_sh_flags() == elfcpp::SHF_ALLOC); + + Stringpool::Key name_key; + const char* name = this->namepool_.add(".eh_frame", false, &name_key); + + Output_section* os = this->get_output_section(name, name_key, + elfcpp::SHT_PROGBITS, + elfcpp::SHF_ALLOC); + + if (this->eh_frame_section_ == NULL) + { + this->eh_frame_section_ = os; + this->eh_frame_data_ = new Eh_frame(); + os->add_output_section_data(this->eh_frame_data_); + + if (this->options_.create_eh_frame_hdr()) + { + Stringpool::Key hdr_name_key; + const char* hdr_name = this->namepool_.add(".eh_frame_hdr", + false, + &hdr_name_key); + Output_section* hdr_os = + this->get_output_section(hdr_name, hdr_name_key, + elfcpp::SHT_PROGBITS, + elfcpp::SHF_ALLOC); + + Eh_frame_hdr* hdr_posd = new Eh_frame_hdr(os, this->eh_frame_data_); + hdr_os->add_output_section_data(hdr_posd); + + hdr_os->set_after_input_sections(); + + Output_segment* hdr_oseg = + new Output_segment(elfcpp::PT_GNU_EH_FRAME, elfcpp::PF_R); + this->segment_list_.push_back(hdr_oseg); + hdr_oseg->add_output_section(hdr_os, elfcpp::PF_R); + + this->eh_frame_data_->set_eh_frame_hdr(hdr_posd); + } + } + + gold_assert(this->eh_frame_section_ == os); + + if (this->eh_frame_data_->add_ehframe_input_section(object, + symbols, + symbols_size, + symbol_names, + symbol_names_size, + shndx, + reloc_shndx, + reloc_type)) + *off = -1; + else + { + // We couldn't handle this .eh_frame section for some reason. + // Add it as a normal section. + *off = os->add_input_section(object, shndx, name, shdr, reloc_shndx); + } return os; } @@ -222,7 +368,7 @@ Layout::add_output_section_data(const char* name, elfcpp::Elf_Word type, { // Canonicalize the name. Stringpool::Key name_key; - name = this->namepool_.add(name, &name_key); + name = this->namepool_.add(name, true, &name_key); Output_section* os = this->get_output_section(name, name_key, type, flags); os->add_output_section_data(posd); @@ -241,6 +387,22 @@ Layout::section_flags_to_segment(elfcpp::Elf_Xword flags) return ret; } +// Sometimes we compress sections. This is typically done for +// sections that are not part of normal program execution (such as +// .debug_* sections), and where the readers of these sections know +// how to deal with compressed sections. (To make it easier for them, +// we will rename the ouput section in such cases from .foo to +// .foo.zlib.nnnn, where nnnn is the uncompressed size.) This routine +// doesn't say for certain whether we'll compress -- it depends on +// commandline options as well -- just whether this section is a +// candidate for compression. + +static bool +is_compressible_debug_section(const char* secname) +{ + return (strncmp(secname, ".debug", sizeof(".debug") - 1) == 0); +} + // Make a new Output_section, and attach it to segments as // appropriate. @@ -248,7 +410,14 @@ Output_section* Layout::make_output_section(const char* name, elfcpp::Elf_Word type, elfcpp::Elf_Xword flags) { - Output_section* os = new Output_section(name, type, flags); + Output_section* os; + if ((flags & elfcpp::SHF_ALLOC) == 0 + && this->options_.compress_debug_sections() + && is_compressible_debug_section(name)) + os = new Output_compressed_section(&this->options_, name, type, flags); + else + os = new Output_section(name, type, flags); + this->section_list_.push_back(os); if ((flags & elfcpp::SHF_ALLOC) == 0) @@ -330,6 +499,27 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type, return os; } +// Handle the .note.GNU-stack section at layout time. SEEN_GNU_STACK +// is whether we saw a .note.GNU-stack section in the object file. +// GNU_STACK_FLAGS is the section flags. The flags give the +// protection required for stack memory. We record this in an +// executable as a PT_GNU_STACK segment. If an object file does not +// have a .note.GNU-stack segment, we must assume that it is an old +// object. On some targets that will force an executable stack. + +void +Layout::layout_gnu_stack(bool seen_gnu_stack, uint64_t gnu_stack_flags) +{ + if (!seen_gnu_stack) + this->input_without_gnu_stack_note_ = true; + else + { + this->input_with_gnu_stack_note_ = true; + if ((gnu_stack_flags & elfcpp::SHF_EXECINSTR) != 0) + this->input_requires_executable_stack_ = true; + } +} + // Create the dynamic sections which are needed before we read the // relocs. @@ -337,10 +527,10 @@ void Layout::create_initial_dynamic_sections(const Input_objects* input_objects, Symbol_table* symtab) { - if (!input_objects->any_dynamic()) + if (parameters->doing_static_link()) return; - const char* dynamic_name = this->namepool_.add(".dynamic", NULL); + const char* dynamic_name = this->namepool_.add(".dynamic", false, NULL); this->dynamic_section_ = this->make_output_section(dynamic_name, elfcpp::SHT_DYNAMIC, (elfcpp::SHF_ALLOC @@ -351,8 +541,7 @@ Layout::create_initial_dynamic_sections(const Input_objects* input_objects, elfcpp::STT_OBJECT, elfcpp::STB_LOCAL, elfcpp::STV_HIDDEN, 0, false, false); - this->dynamic_data_ = new Output_data_dynamic(input_objects->target(), - &this->dynpool_); + this->dynamic_data_ = new Output_data_dynamic(&this->dynpool_); this->dynamic_section_->add_output_section_data(this->dynamic_data_); } @@ -466,12 +655,16 @@ off_t Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab) { Target* const target = input_objects->target(); - const int size = target->get_size(); target->finalize_sections(this); + this->count_local_symbols(input_objects); + + this->create_gold_note(); + this->create_executable_stack_info(target); + Output_segment* phdr_seg = NULL; - if (input_objects->any_dynamic()) + if (!parameters->doing_static_link()) { // There was a dynamic object in the link. We need to create // some information for the dynamic linker. @@ -486,13 +679,14 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab) std::vector dynamic_symbols; unsigned int local_dynamic_count; Versions versions; - this->create_dynamic_symtab(target, symtab, &dynstr, + this->create_dynamic_symtab(input_objects, target, symtab, &dynstr, &local_dynamic_count, &dynamic_symbols, &versions); // Create the .interp section to hold the name of the // interpreter, and put it in a PT_INTERP segment. - this->create_interp(target); + if (!parameters->output_is_shared()) + this->create_interp(target); // Finish the .dynamic section to hold the dynamic data, and put // it in a PT_DYNAMIC segment. @@ -504,7 +698,7 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab) // Create the version sections. We can't do this until the // dynamic string table is complete. - this->create_version_sections(target, &versions, local_dynamic_count, + this->create_version_sections(&versions, symtab, local_dynamic_count, dynamic_symbols, dynstr); } @@ -513,10 +707,8 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab) Output_segment* load_seg = this->find_first_load_seg(); // Lay out the segment headers. - bool big_endian = target->is_big_endian(); Output_segment_headers* segment_headers; - segment_headers = new Output_segment_headers(size, big_endian, - this->segment_list_); + segment_headers = new Output_segment_headers(this->segment_list_); load_seg->add_initial_output_data(segment_headers); this->special_output_list_.push_back(segment_headers); if (phdr_seg != NULL) @@ -524,16 +716,12 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab) // Lay out the file header. Output_file_header* file_header; - file_header = new Output_file_header(size, - big_endian, - target, - symtab, - segment_headers); + file_header = new Output_file_header(target, symtab, segment_headers); load_seg->add_initial_output_data(file_header); this->special_output_list_.push_back(file_header); // We set the output section indexes in set_segment_offsets and - // set_section_offsets. + // set_section_indexes. unsigned int shndx = 1; // Set the file offsets of all the segments, and all the sections @@ -541,26 +729,170 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab) off_t off = this->set_segment_offsets(target, load_seg, &shndx); // Create the symbol table sections. - this->create_symtab_sections(size, input_objects, symtab, &off); + this->create_symtab_sections(input_objects, symtab, &off); + if (!parameters->doing_static_link()) + this->assign_local_dynsym_offsets(input_objects); // Create the .shstrtab section. Output_section* shstrtab_section = this->create_shstrtab(); - // Set the file offsets of all the sections not associated with - // segments. - off = this->set_section_offsets(off, &shndx); + // Set the file offsets of all the non-data sections which don't + // have to wait for the input sections. + off = this->set_section_offsets(off, BEFORE_INPUT_SECTIONS_PASS); + + // Now that all sections have been created, set the section indexes. + shndx = this->set_section_indexes(shndx); // Create the section table header. - Output_section_headers* oshdrs = this->create_shdrs(size, big_endian, &off); + this->create_shdrs(&off); - file_header->set_section_info(oshdrs, shstrtab_section); + file_header->set_section_info(this->section_headers_, shstrtab_section); - // Now we know exactly where everything goes in the output file. + // Now we know exactly where everything goes in the output file + // (except for non-allocated sections which require postprocessing). Output_data::layout_complete(); + this->output_file_size_ = off; + return off; } +// Create a .note section for an executable or shared library. This +// records the version of gold used to create the binary. + +void +Layout::create_gold_note() +{ + if (parameters->output_is_object()) + return; + + // Authorities all agree that the values in a .note field should + // be aligned on 4-byte boundaries for 32-bit binaries. However, + // they differ on what the alignment is for 64-bit binaries. + // The GABI says unambiguously they take 8-byte alignment: + // http://sco.com/developers/gabi/latest/ch5.pheader.html#note_section + // Other documentation says alignment should always be 4 bytes: + // http://www.netbsd.org/docs/kernel/elf-notes.html#note-format + // GNU ld and GNU readelf both support the latter (at least as of + // version 2.16.91), and glibc always generates the latter for + // .note.ABI-tag (as of version 1.6), so that's the one we go with + // here. +#ifdef GABI_FORMAT_FOR_DOTNOTE_SECTION // This is not defined by default. + const int size = parameters->get_size(); +#else + const int size = 32; +#endif + + // The contents of the .note section. + const char* name = "GNU"; + std::string desc(std::string("gold ") + gold::get_version_string()); + size_t namesz = strlen(name) + 1; + size_t aligned_namesz = align_address(namesz, size / 8); + size_t descsz = desc.length() + 1; + size_t aligned_descsz = align_address(descsz, size / 8); + const int note_type = 4; + + size_t notesz = 3 * (size / 8) + aligned_namesz + aligned_descsz; + + unsigned char buffer[128]; + gold_assert(sizeof buffer >= notesz); + memset(buffer, 0, notesz); + + bool is_big_endian = parameters->is_big_endian(); + + if (size == 32) + { + if (!is_big_endian) + { + elfcpp::Swap<32, false>::writeval(buffer, namesz); + elfcpp::Swap<32, false>::writeval(buffer + 4, descsz); + elfcpp::Swap<32, false>::writeval(buffer + 8, note_type); + } + else + { + elfcpp::Swap<32, true>::writeval(buffer, namesz); + elfcpp::Swap<32, true>::writeval(buffer + 4, descsz); + elfcpp::Swap<32, true>::writeval(buffer + 8, note_type); + } + } + else if (size == 64) + { + if (!is_big_endian) + { + elfcpp::Swap<64, false>::writeval(buffer, namesz); + elfcpp::Swap<64, false>::writeval(buffer + 8, descsz); + elfcpp::Swap<64, false>::writeval(buffer + 16, note_type); + } + else + { + elfcpp::Swap<64, true>::writeval(buffer, namesz); + elfcpp::Swap<64, true>::writeval(buffer + 8, descsz); + elfcpp::Swap<64, true>::writeval(buffer + 16, note_type); + } + } + else + gold_unreachable(); + + memcpy(buffer + 3 * (size / 8), name, namesz); + memcpy(buffer + 3 * (size / 8) + aligned_namesz, desc.data(), descsz); + + const char* note_name = this->namepool_.add(".note", false, NULL); + Output_section* os = this->make_output_section(note_name, + elfcpp::SHT_NOTE, + 0); + Output_section_data* posd = new Output_data_const(buffer, notesz, + size / 8); + os->add_output_section_data(posd); +} + +// Record whether the stack should be executable. This can be set +// from the command line using the -z execstack or -z noexecstack +// options. Otherwise, if any input file has a .note.GNU-stack +// section with the SHF_EXECINSTR flag set, the stack should be +// executable. Otherwise, if at least one input file a +// .note.GNU-stack section, and some input file has no .note.GNU-stack +// section, we use the target default for whether the stack should be +// executable. Otherwise, we don't generate a stack note. When +// generating a object file, we create a .note.GNU-stack section with +// the appropriate marking. When generating an executable or shared +// library, we create a PT_GNU_STACK segment. + +void +Layout::create_executable_stack_info(const Target* target) +{ + bool is_stack_executable; + if (this->options_.is_execstack_set()) + is_stack_executable = this->options_.is_stack_executable(); + else if (!this->input_with_gnu_stack_note_) + return; + else + { + if (this->input_requires_executable_stack_) + is_stack_executable = true; + else if (this->input_without_gnu_stack_note_) + is_stack_executable = target->is_default_stack_executable(); + else + is_stack_executable = false; + } + + if (parameters->output_is_object()) + { + const char* name = this->namepool_.add(".note.GNU-stack", false, NULL); + elfcpp::Elf_Xword flags = 0; + if (is_stack_executable) + flags |= elfcpp::SHF_EXECINSTR; + this->make_output_section(name, elfcpp::SHT_PROGBITS, flags); + } + else + { + int flags = elfcpp::PF_R | elfcpp::PF_W; + if (is_stack_executable) + flags |= elfcpp::PF_X; + Output_segment* oseg = new Output_segment(elfcpp::PT_GNU_STACK, flags); + this->segment_list_.push_back(oseg); + } +} + // Return whether SEG1 should be before SEG2 in the output file. This // is based entirely on the segment type and flags. When this is // called the segment addresses has normally not yet been set. @@ -659,7 +991,13 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg, // Find the PT_LOAD segments, and set their addresses and offsets // and their section's addresses and offsets. - uint64_t addr = target->text_segment_address(); + uint64_t addr; + if (parameters->output_is_shared()) + addr = 0; + else if (options_.user_set_text_segment_address()) + addr = options_.text_segment_address(); + else + addr = target->default_text_segment_address(); off_t off = 0; bool was_readonly = false; for (Segment_list::iterator p = this->segment_list_.begin(); @@ -744,6 +1082,10 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg, (*p)->set_offset(); } + // Set the TLS offsets for each section in the PT_TLS segment. + if (this->tls_segment_ != NULL) + this->tls_segment_->set_tls_offsets(); + return off; } @@ -751,40 +1093,92 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg, // segment. off_t -Layout::set_section_offsets(off_t off, unsigned int* pshndx) +Layout::set_section_offsets(off_t off, Layout::Section_offset_pass pass) { for (Section_list::iterator p = this->unattached_section_list_.begin(); p != this->unattached_section_list_.end(); ++p) { - (*p)->set_out_shndx(*pshndx); - ++*pshndx; - if ((*p)->offset() != -1) + // The symtab section is handled in create_symtab_sections. + if (*p == this->symtab_section_) continue; + + if (pass == BEFORE_INPUT_SECTIONS_PASS + && (*p)->requires_postprocessing()) + (*p)->create_postprocessing_buffer(); + + if (pass == BEFORE_INPUT_SECTIONS_PASS + && (*p)->after_input_sections()) + continue; + else if (pass == AFTER_INPUT_SECTIONS_PASS + && (!(*p)->after_input_sections() + || (*p)->type() == elfcpp::SHT_STRTAB)) + continue; + else if (pass == STRTAB_AFTER_INPUT_SECTIONS_PASS + && (!(*p)->after_input_sections() + || (*p)->type() != elfcpp::SHT_STRTAB)) + continue; + off = align_address(off, (*p)->addralign()); - (*p)->set_address(0, off); + (*p)->set_file_offset(off); + (*p)->finalize_data_size(); off += (*p)->data_size(); + + // At this point the name must be set. + if (pass != STRTAB_AFTER_INPUT_SECTIONS_PASS) + this->namepool_.add((*p)->name(), false, NULL); } return off; } +// Set the section indexes of all the sections not associated with a +// segment. + +unsigned int +Layout::set_section_indexes(unsigned int shndx) +{ + for (Section_list::iterator p = this->unattached_section_list_.begin(); + p != this->unattached_section_list_.end(); + ++p) + { + (*p)->set_out_shndx(shndx); + ++shndx; + } + return shndx; +} + +// Count the local symbols in the regular symbol table and the dynamic +// symbol table, and build the respective string pools. + +void +Layout::count_local_symbols(const Input_objects* input_objects) +{ + for (Input_objects::Relobj_iterator p = input_objects->relobj_begin(); + p != input_objects->relobj_end(); + ++p) + { + Task_lock_obj tlo(**p); + (*p)->count_local_symbols(&this->sympool_, &this->dynpool_); + } +} + // Create the symbol table sections. Here we also set the final // values of the symbols. At this point all the loadable sections are // fully laid out. void -Layout::create_symtab_sections(int size, const Input_objects* input_objects, +Layout::create_symtab_sections(const Input_objects* input_objects, Symbol_table* symtab, off_t* poff) { int symsize; unsigned int align; - if (size == 32) + if (parameters->get_size() == 32) { symsize = elfcpp::Elf_sizes<32>::sym_size; align = 4; } - else if (size == 64) + else if (parameters->get_size() == 64) { symsize = elfcpp::Elf_sizes<64>::sym_size; align = 8; @@ -820,10 +1214,8 @@ Layout::create_symtab_sections(int size, const Input_objects* input_objects, p != input_objects->relobj_end(); ++p) { - Task_lock_obj tlo(**p); unsigned int index = (*p)->finalize_local_symbols(local_symbol_index, - off, - &this->sympool_); + off); off += (index - local_symbol_index) * symsize; local_symbol_index = index; } @@ -846,39 +1238,43 @@ Layout::create_symtab_sections(int size, const Input_objects* input_objects, off_t locsize = dyn_global_index * this->dynsym_section_->entsize(); dynoff = this->dynsym_section_->offset() + locsize; dyncount = (this->dynsym_section_->data_size() - locsize) / symsize; - gold_assert(dyncount * symsize + gold_assert(static_cast(dyncount * symsize) == this->dynsym_section_->data_size() - locsize); } off = symtab->finalize(local_symcount, off, dynoff, dyn_global_index, dyncount, &this->sympool_); - this->sympool_.set_string_offsets(); + if (!parameters->strip_all()) + { + this->sympool_.set_string_offsets(); - const char* symtab_name = this->namepool_.add(".symtab", NULL); - Output_section* osymtab = this->make_output_section(symtab_name, - elfcpp::SHT_SYMTAB, - 0); - this->symtab_section_ = osymtab; + const char* symtab_name = this->namepool_.add(".symtab", false, NULL); + Output_section* osymtab = this->make_output_section(symtab_name, + elfcpp::SHT_SYMTAB, + 0); + this->symtab_section_ = osymtab; - Output_section_data* pos = new Output_data_space(off - startoff, - align); - osymtab->add_output_section_data(pos); + Output_section_data* pos = new Output_data_fixed_space(off - startoff, + align); + osymtab->add_output_section_data(pos); - const char* strtab_name = this->namepool_.add(".strtab", NULL); - Output_section* ostrtab = this->make_output_section(strtab_name, - elfcpp::SHT_STRTAB, - 0); + const char* strtab_name = this->namepool_.add(".strtab", false, NULL); + Output_section* ostrtab = this->make_output_section(strtab_name, + elfcpp::SHT_STRTAB, + 0); - Output_section_data* pstr = new Output_data_strtab(&this->sympool_); - ostrtab->add_output_section_data(pstr); + Output_section_data* pstr = new Output_data_strtab(&this->sympool_); + ostrtab->add_output_section_data(pstr); - osymtab->set_address(0, startoff); - osymtab->set_link_section(ostrtab); - osymtab->set_info(local_symcount); - osymtab->set_entsize(symsize); + osymtab->set_file_offset(startoff); + osymtab->finalize_data_size(); + osymtab->set_link_section(ostrtab); + osymtab->set_info(local_symcount); + osymtab->set_entsize(symsize); - *poff = off; + *poff = off; + } } // Create the .shstrtab section, which holds the names of the @@ -891,12 +1287,15 @@ Layout::create_shstrtab() // FIXME: We don't need to create a .shstrtab section if we are // stripping everything. - const char* name = this->namepool_.add(".shstrtab", NULL); - - this->namepool_.set_string_offsets(); + const char* name = this->namepool_.add(".shstrtab", false, NULL); Output_section* os = this->make_output_section(name, elfcpp::SHT_STRTAB, 0); + // We can't write out this section until we've set all the section + // names, and we don't set the names of compressed output sections + // until relocations are complete. + os->set_after_input_sections(); + Output_section_data* posd = new Output_data_strtab(&this->namepool_); os->add_output_section_data(posd); @@ -906,26 +1305,26 @@ Layout::create_shstrtab() // Create the section headers. SIZE is 32 or 64. OFF is the file // offset. -Output_section_headers* -Layout::create_shdrs(int size, bool big_endian, off_t* poff) +void +Layout::create_shdrs(off_t* poff) { Output_section_headers* oshdrs; - oshdrs = new Output_section_headers(size, big_endian, this, + oshdrs = new Output_section_headers(this, &this->segment_list_, &this->unattached_section_list_, &this->namepool_); off_t off = align_address(*poff, oshdrs->addralign()); - oshdrs->set_address(0, off); + oshdrs->set_address_and_file_offset(0, off); off += oshdrs->data_size(); *poff = off; - this->special_output_list_.push_back(oshdrs); - return oshdrs; + this->section_headers_ = oshdrs; } // Create the dynamic symbol table. void -Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab, +Layout::create_dynamic_symtab(const Input_objects* input_objects, + const Target* target, Symbol_table* symtab, Output_section **pdynstr, unsigned int* plocal_dynamic_count, std::vector* pdynamic_symbols, @@ -951,23 +1350,27 @@ Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab, } } - // FIXME: Some targets apparently require local symbols in the - // dynamic symbol table. Here is where we will have to count them, - // and set the dynamic symbol indexes, and add the names to - // this->dynpool_. + // Count the local symbols that need to go in the dynamic symbol table, + // and set the dynamic symbol indexes. + for (Input_objects::Relobj_iterator p = input_objects->relobj_begin(); + p != input_objects->relobj_end(); + ++p) + { + unsigned int new_index = (*p)->set_local_dynsym_indexes(index); + index = new_index; + } unsigned int local_symcount = index; *plocal_dynamic_count = local_symcount; // FIXME: We have to tell set_dynsym_indexes whether the // -E/--export-dynamic option was used. - index = symtab->set_dynsym_indexes(&this->options_, target, index, - pdynamic_symbols, &this->dynpool_, - pversions); + index = symtab->set_dynsym_indexes(target, index, pdynamic_symbols, + &this->dynpool_, pversions); int symsize; unsigned int align; - const int size = target->get_size(); + const int size = parameters->get_size(); if (size == 32) { symsize = elfcpp::Elf_sizes<32>::sym_size; @@ -983,13 +1386,13 @@ Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab, // Create the dynamic symbol table section. - const char* dynsym_name = this->namepool_.add(".dynsym", NULL); + const char* dynsym_name = this->namepool_.add(".dynsym", false, NULL); Output_section* dynsym = this->make_output_section(dynsym_name, elfcpp::SHT_DYNSYM, elfcpp::SHF_ALLOC); - Output_section_data* odata = new Output_data_space(index * symsize, - align); + Output_section_data* odata = new Output_data_fixed_space(index * symsize, + align); dynsym->add_output_section_data(odata); dynsym->set_info(local_symcount); @@ -1004,7 +1407,7 @@ Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab, // Create the dynamic string table section. - const char* dynstr_name = this->namepool_.add(".dynstr", NULL); + const char* dynstr_name = this->namepool_.add(".dynstr", false, NULL); Output_section* dynstr = this->make_output_section(dynstr_name, elfcpp::SHT_STRTAB, elfcpp::SHF_ALLOC); @@ -1026,10 +1429,10 @@ Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab, unsigned char* phash; unsigned int hashlen; - Dynobj::create_elf_hash_table(target, *pdynamic_symbols, local_symcount, + Dynobj::create_elf_hash_table(*pdynamic_symbols, local_symcount, &phash, &hashlen); - const char* hash_name = this->namepool_.add(".hash", NULL); + const char* hash_name = this->namepool_.add(".hash", false, NULL); Output_section* hashsec = this->make_output_section(hash_name, elfcpp::SHT_HASH, elfcpp::SHF_ALLOC); @@ -1045,10 +1448,33 @@ Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab, odyn->add_section_address(elfcpp::DT_HASH, hashsec); } +// Assign offsets to each local portion of the dynamic symbol table. + +void +Layout::assign_local_dynsym_offsets(const Input_objects* input_objects) +{ + Output_section* dynsym = this->dynsym_section_; + gold_assert(dynsym != NULL); + + off_t off = dynsym->offset(); + + // Skip the dummy symbol at the start of the section. + off += dynsym->entsize(); + + for (Input_objects::Relobj_iterator p = input_objects->relobj_begin(); + p != input_objects->relobj_end(); + ++p) + { + unsigned int count = (*p)->set_local_dynsym_offset(off); + off += count * dynsym->entsize(); + } +} + // Create the version sections. void -Layout::create_version_sections(const Target* target, const Versions* versions, +Layout::create_version_sections(const Versions* versions, + const Symbol_table* symtab, unsigned int local_symcount, const std::vector& dynamic_symbols, const Output_section* dynstr) @@ -1056,14 +1482,14 @@ Layout::create_version_sections(const Target* target, const Versions* versions, if (!versions->any_defs() && !versions->any_needs()) return; - if (target->get_size() == 32) + if (parameters->get_size() == 32) { - if (target->is_big_endian()) + if (parameters->is_big_endian()) { #ifdef HAVE_TARGET_32_BIG this->sized_create_version_sections SELECT_SIZE_ENDIAN_NAME(32, true)( - versions, local_symcount, dynamic_symbols, dynstr + versions, symtab, local_symcount, dynamic_symbols, dynstr SELECT_SIZE_ENDIAN(32, true)); #else gold_unreachable(); @@ -1074,21 +1500,21 @@ Layout::create_version_sections(const Target* target, const Versions* versions, #ifdef HAVE_TARGET_32_LITTLE this->sized_create_version_sections SELECT_SIZE_ENDIAN_NAME(32, false)( - versions, local_symcount, dynamic_symbols, dynstr + versions, symtab, local_symcount, dynamic_symbols, dynstr SELECT_SIZE_ENDIAN(32, false)); #else gold_unreachable(); #endif } } - else if (target->get_size() == 64) + else if (parameters->get_size() == 64) { - if (target->is_big_endian()) + if (parameters->is_big_endian()) { #ifdef HAVE_TARGET_64_BIG this->sized_create_version_sections SELECT_SIZE_ENDIAN_NAME(64, true)( - versions, local_symcount, dynamic_symbols, dynstr + versions, symtab, local_symcount, dynamic_symbols, dynstr SELECT_SIZE_ENDIAN(64, true)); #else gold_unreachable(); @@ -1099,7 +1525,7 @@ Layout::create_version_sections(const Target* target, const Versions* versions, #ifdef HAVE_TARGET_64_LITTLE this->sized_create_version_sections SELECT_SIZE_ENDIAN_NAME(64, false)( - versions, local_symcount, dynamic_symbols, dynstr + versions, symtab, local_symcount, dynamic_symbols, dynstr SELECT_SIZE_ENDIAN(64, false)); #else gold_unreachable(); @@ -1116,12 +1542,13 @@ template void Layout::sized_create_version_sections( const Versions* versions, + const Symbol_table* symtab, unsigned int local_symcount, const std::vector& dynamic_symbols, const Output_section* dynstr ACCEPT_SIZE_ENDIAN) { - const char* vname = this->namepool_.add(".gnu.version", NULL); + const char* vname = this->namepool_.add(".gnu.version", false, NULL); Output_section* vsec = this->make_output_section(vname, elfcpp::SHT_GNU_versym, elfcpp::SHF_ALLOC); @@ -1129,7 +1556,7 @@ Layout::sized_create_version_sections( unsigned char* vbuf; unsigned int vsize; versions->symbol_section_contents SELECT_SIZE_ENDIAN_NAME(size, big_endian)( - &this->dynpool_, local_symcount, dynamic_symbols, &vbuf, &vsize + symtab, &this->dynpool_, local_symcount, dynamic_symbols, &vbuf, &vsize SELECT_SIZE_ENDIAN(size, big_endian)); Output_section_data* vdata = new Output_data_const_buffer(vbuf, vsize, 2); @@ -1143,7 +1570,7 @@ Layout::sized_create_version_sections( if (versions->any_defs()) { - const char* vdname = this->namepool_.add(".gnu.version_d", NULL); + const char* vdname = this->namepool_.add(".gnu.version_d", false, NULL); Output_section *vdsec; vdsec = this->make_output_section(vdname, elfcpp::SHT_GNU_verdef, elfcpp::SHF_ALLOC); @@ -1169,7 +1596,7 @@ Layout::sized_create_version_sections( if (versions->any_needs()) { - const char* vnname = this->namepool_.add(".gnu.version_r", NULL); + const char* vnname = this->namepool_.add(".gnu.version_r", false, NULL); Output_section* vnsec; vnsec = this->make_output_section(vnname, elfcpp::SHT_GNU_verneed, elfcpp::SHF_ALLOC); @@ -1210,7 +1637,7 @@ Layout::create_interp(const Target* target) Output_section_data* odata = new Output_data_const(interp, len, 1); - const char* interp_name = this->namepool_.add(".interp", NULL); + const char* interp_name = this->namepool_.add(".interp", false, NULL); Output_section* osec = this->make_output_section(interp_name, elfcpp::SHT_PROGBITS, elfcpp::SHF_ALLOC); @@ -1264,24 +1691,45 @@ Layout::finish_dynamic_section(const Input_objects* input_objects, ++p) { if (rpath_val.empty()) - rpath_val = *p; + rpath_val = p->name(); else { // Eliminate duplicates. General_options::Dir_list::const_iterator q; for (q = rpath.begin(); q != p; ++q) - if (strcmp(*q, *p) == 0) + if (q->name() == p->name()) break; if (q == p) { rpath_val += ':'; - rpath_val += *p; + rpath_val += p->name(); } } } odyn->add_string(elfcpp::DT_RPATH, rpath_val); } + + // Look for text segments that have dynamic relocations. + bool have_textrel = false; + for (Segment_list::const_iterator p = this->segment_list_.begin(); + p != this->segment_list_.end(); + ++p) + { + if (((*p)->flags() & elfcpp::PF_W) == 0 + && (*p)->dynamic_reloc_count() > 0) + { + have_textrel = true; + break; + } + } + + // Add a DT_FLAGS entry. We add it even if no flags are set so that + // post-link tools can easily modify these flags if desired. + unsigned int flags = 0; + if (have_textrel) + flags |= elfcpp::DF_TEXTREL; + odyn->add_constant(elfcpp::DT_FLAGS, flags); } // The mapping of .gnu.linkonce section names to real section names. @@ -1349,41 +1797,68 @@ Layout::output_section_name(const char* name, size_t* plen) return Layout::linkonce_output_name(name, plen); } - // If the section name has no '.', or only an initial '.', we use - // the name unchanged (i.e., ".text" is unchanged). - - // Otherwise, if the section name does not include ".rel", we drop - // the last '.' and everything that follows (i.e., ".text.XXX" - // becomes ".text"). - - // Otherwise, if the section name has zero or one '.' after the - // ".rel", we use the name unchanged (i.e., ".rel.text" is - // unchanged). - - // Otherwise, we drop the last '.' and everything that follows - // (i.e., ".rel.text.XXX" becomes ".rel.text"). + // gcc 4.3 generates the following sorts of section names when it + // needs a section name specific to a function: + // .text.FN + // .rodata.FN + // .sdata2.FN + // .data.FN + // .data.rel.FN + // .data.rel.local.FN + // .data.rel.ro.FN + // .data.rel.ro.local.FN + // .sdata.FN + // .bss.FN + // .sbss.FN + // .tdata.FN + // .tbss.FN + + // The GNU linker maps all of those to the part before the .FN, + // except that .data.rel.local.FN is mapped to .data, and + // .data.rel.ro.local.FN is mapped to .data.rel.ro. The sections + // beginning with .data.rel.ro.local are grouped together. + + // For an anonymous namespace, the string FN can contain a '.'. + + // Also of interest: .rodata.strN.N, .rodata.cstN, both of which the + // GNU linker maps to .rodata. + + // The .data.rel.ro sections enable a security feature triggered by + // the -z relro option. Section which need to be relocated at + // program startup time but which may be readonly after startup are + // grouped into .data.rel.ro. They are then put into a PT_GNU_RELRO + // segment. The dynamic linker will make that segment writable, + // perform relocations, and then make it read-only. FIXME: We do + // not yet implement this optimization. + + // It is hard to handle this in a principled way. + + // These are the rules we follow: + + // If the section name has no initial '.', or no dot other than an + // initial '.', we use the name unchanged (i.e., "mysection" and + // ".text" are unchanged). + + // If the name starts with ".data.rel.ro" we use ".data.rel.ro". + + // Otherwise, we drop the second '.' and everything that comes after + // it (i.e., ".text.XXX" becomes ".text"). const char* s = name; - if (*s == '.') - ++s; + if (*s != '.') + return name; + ++s; const char* sdot = strchr(s, '.'); if (sdot == NULL) return name; - const char* srel = strstr(s, ".rel"); - if (srel == NULL) + const char* const data_rel_ro = ".data.rel.ro"; + if (strncmp(name, data_rel_ro, strlen(data_rel_ro)) == 0) { - *plen = sdot - name; - return name; + *plen = strlen(data_rel_ro); + return data_rel_ro; } - sdot = strchr(srel + 1, '.'); - if (sdot == NULL) - return name; - sdot = strchr(sdot + 1, '.'); - if (sdot == NULL) - return name; - *plen = sdot - name; return name; } @@ -1430,25 +1905,43 @@ Layout::add_comdat(const char* signature, bool group) } } -// Write out data not associated with a section or the symbol table. +// Write out the Output_sections. Most won't have anything to write, +// since most of the data will come from input sections which are +// handled elsewhere. But some Output_sections do have Output_data. void -Layout::write_data(const Symbol_table* symtab, const Target* target, - Output_file* of) const +Layout::write_output_sections(Output_file* of) const { - const Output_section* symtab_section = this->symtab_section_; for (Section_list::const_iterator p = this->section_list_.begin(); p != this->section_list_.end(); ++p) { - if ((*p)->needs_symtab_index()) + if (!(*p)->after_input_sections()) + (*p)->write(of); + } +} + +// Write out data not associated with a section or the symbol table. + +void +Layout::write_data(const Symbol_table* symtab, Output_file* of) const +{ + if (!parameters->strip_all()) + { + const Output_section* symtab_section = this->symtab_section_; + for (Section_list::const_iterator p = this->section_list_.begin(); + p != this->section_list_.end(); + ++p) { - gold_assert(symtab_section != NULL); - unsigned int index = (*p)->symtab_index(); - gold_assert(index > 0 && index != -1U); - off_t off = (symtab_section->offset() - + index * symtab_section->entsize()); - symtab->write_section_symbol(target, *p, of, off); + if ((*p)->needs_symtab_index()) + { + gold_assert(symtab_section != NULL); + unsigned int index = (*p)->symtab_index(); + gold_assert(index > 0 && index != -1U); + off_t off = (symtab_section->offset() + + index * symtab_section->entsize()); + symtab->write_section_symbol(*p, of, off); + } } } @@ -1464,19 +1957,10 @@ Layout::write_data(const Symbol_table* symtab, const Target* target, gold_assert(index > 0 && index != -1U); off_t off = (dynsym_section->offset() + index * dynsym_section->entsize()); - symtab->write_section_symbol(target, *p, of, off); + symtab->write_section_symbol(*p, of, off); } } - // Write out the Output_sections. Most won't have anything to - // write, since most of the data will come from input sections which - // are handled elsewhere. But some Output_sections do have - // Output_data. - for (Section_list::const_iterator p = this->section_list_.begin(); - p != this->section_list_.end(); - ++p) - (*p)->write(of); - // Write out the Output_data which are not in an Output_section. for (Data_list::const_iterator p = this->special_output_list_.begin(); p != this->special_output_list_.end(); @@ -1484,6 +1968,101 @@ Layout::write_data(const Symbol_table* symtab, const Target* target, (*p)->write(of); } +// Write out the Output_sections which can only be written after the +// input sections are complete. + +void +Layout::write_sections_after_input_sections(Output_file* of) +{ + // Determine the final section offsets, and thus the final output + // file size. Note we finalize the .shstrab last, to allow the + // after_input_section sections to modify their section-names before + // writing. + off_t off = this->output_file_size_; + off = this->set_section_offsets(off, AFTER_INPUT_SECTIONS_PASS); + + // Now that we've finalized the names, we can finalize the shstrab. + off = this->set_section_offsets(off, STRTAB_AFTER_INPUT_SECTIONS_PASS); + + if (off > this->output_file_size_) + { + of->resize(off); + this->output_file_size_ = off; + } + + for (Section_list::const_iterator p = this->section_list_.begin(); + p != this->section_list_.end(); + ++p) + { + if ((*p)->after_input_sections()) + (*p)->write(of); + } + + for (Section_list::const_iterator p = this->unattached_section_list_.begin(); + p != this->unattached_section_list_.end(); + ++p) + { + if ((*p)->after_input_sections()) + (*p)->write(of); + } + + this->section_headers_->write(of); +} + +// Print statistical information to stderr. This is used for --stats. + +void +Layout::print_stats() const +{ + this->namepool_.print_stats("section name pool"); + this->sympool_.print_stats("output symbol name pool"); + this->dynpool_.print_stats("dynamic name pool"); +} + +// Write_sections_task methods. + +// We can always run this task. + +Task::Is_runnable_type +Write_sections_task::is_runnable(Workqueue*) +{ + return IS_RUNNABLE; +} + +// We need to unlock both OUTPUT_SECTIONS_BLOCKER and FINAL_BLOCKER +// when finished. + +class Write_sections_task::Write_sections_locker : public Task_locker +{ + public: + Write_sections_locker(Task_token& output_sections_blocker, + Task_token& final_blocker, + Workqueue* workqueue) + : output_sections_block_(output_sections_blocker, workqueue), + final_block_(final_blocker, workqueue) + { } + + private: + Task_block_token output_sections_block_; + Task_block_token final_block_; +}; + +Task_locker* +Write_sections_task::locks(Workqueue* workqueue) +{ + return new Write_sections_locker(*this->output_sections_blocker_, + *this->final_blocker_, + workqueue); +} + +// Run the task--write out the data. + +void +Write_sections_task::run(Workqueue*) +{ + this->layout_->write_output_sections(this->of_); +} + // Write_data_task methods. // We can always run this task. @@ -1507,7 +2086,7 @@ Write_data_task::locks(Workqueue* workqueue) void Write_data_task::run(Workqueue*) { - this->layout_->write_data(this->symtab_, this->target_, this->of_); + this->layout_->write_data(this->symtab_, this->of_); } // Write_symbols_task methods. @@ -1533,8 +2112,36 @@ Write_symbols_task::locks(Workqueue* workqueue) void Write_symbols_task::run(Workqueue*) { - this->symtab_->write_globals(this->target_, this->sympool_, this->dynpool_, - this->of_); + this->symtab_->write_globals(this->input_objects_, this->sympool_, + this->dynpool_, this->of_); +} + +// Write_after_input_sections_task methods. + +// We can only run this task after the input sections have completed. + +Task::Is_runnable_type +Write_after_input_sections_task::is_runnable(Workqueue*) +{ + if (this->input_sections_blocker_->is_blocked()) + return IS_BLOCKED; + return IS_RUNNABLE; +} + +// We need to unlock FINAL_BLOCKER when finished. + +Task_locker* +Write_after_input_sections_task::locks(Workqueue* workqueue) +{ + return new Task_locker_block(*this->final_blocker_, workqueue); +} + +// Run the task. + +void +Write_after_input_sections_task::run(Workqueue*) +{ + this->layout_->write_sections_after_input_sections(this->of_); } // Close_task_runner methods. @@ -1553,30 +2160,97 @@ Close_task_runner::run(Workqueue*) #ifdef HAVE_TARGET_32_LITTLE template Output_section* -Layout::layout<32, false>(Relobj* object, unsigned int shndx, const char* name, - const elfcpp::Shdr<32, false>& shdr, off_t*); +Layout::layout<32, false>(Sized_relobj<32, false>* object, unsigned int shndx, + const char* name, + const elfcpp::Shdr<32, false>& shdr, + unsigned int, unsigned int, off_t*); #endif #ifdef HAVE_TARGET_32_BIG template Output_section* -Layout::layout<32, true>(Relobj* object, unsigned int shndx, const char* name, - const elfcpp::Shdr<32, true>& shdr, off_t*); +Layout::layout<32, true>(Sized_relobj<32, true>* object, unsigned int shndx, + const char* name, + const elfcpp::Shdr<32, true>& shdr, + unsigned int, unsigned int, off_t*); #endif #ifdef HAVE_TARGET_64_LITTLE template Output_section* -Layout::layout<64, false>(Relobj* object, unsigned int shndx, const char* name, - const elfcpp::Shdr<64, false>& shdr, off_t*); +Layout::layout<64, false>(Sized_relobj<64, false>* object, unsigned int shndx, + const char* name, + const elfcpp::Shdr<64, false>& shdr, + unsigned int, unsigned int, off_t*); #endif #ifdef HAVE_TARGET_64_BIG template Output_section* -Layout::layout<64, true>(Relobj* object, unsigned int shndx, const char* name, - const elfcpp::Shdr<64, true>& shdr, off_t*); +Layout::layout<64, true>(Sized_relobj<64, true>* object, unsigned int shndx, + const char* name, + const elfcpp::Shdr<64, true>& shdr, + unsigned int, unsigned int, off_t*); #endif +#ifdef HAVE_TARGET_32_LITTLE +template +Output_section* +Layout::layout_eh_frame<32, false>(Sized_relobj<32, false>* object, + const unsigned char* symbols, + off_t symbols_size, + const unsigned char* symbol_names, + off_t symbol_names_size, + unsigned int shndx, + const elfcpp::Shdr<32, false>& shdr, + unsigned int reloc_shndx, + unsigned int reloc_type, + off_t* off); +#endif + +#ifdef HAVE_TARGET_32_BIG +template +Output_section* +Layout::layout_eh_frame<32, true>(Sized_relobj<32, true>* object, + const unsigned char* symbols, + off_t symbols_size, + const unsigned char* symbol_names, + off_t symbol_names_size, + unsigned int shndx, + const elfcpp::Shdr<32, true>& shdr, + unsigned int reloc_shndx, + unsigned int reloc_type, + off_t* off); +#endif + +#ifdef HAVE_TARGET_64_LITTLE +template +Output_section* +Layout::layout_eh_frame<64, false>(Sized_relobj<64, false>* object, + const unsigned char* symbols, + off_t symbols_size, + const unsigned char* symbol_names, + off_t symbol_names_size, + unsigned int shndx, + const elfcpp::Shdr<64, false>& shdr, + unsigned int reloc_shndx, + unsigned int reloc_type, + off_t* off); +#endif + +#ifdef HAVE_TARGET_64_BIG +template +Output_section* +Layout::layout_eh_frame<64, true>(Sized_relobj<64, true>* object, + const unsigned char* symbols, + off_t symbols_size, + const unsigned char* symbol_names, + off_t symbol_names_size, + unsigned int shndx, + const elfcpp::Shdr<64, true>& shdr, + unsigned int reloc_shndx, + unsigned int reloc_type, + off_t* off); +#endif } // End namespace gold.