diff options
-rw-r--r-- | gold/ChangeLog | 99 | ||||
-rw-r--r-- | gold/Makefile.am | 2 | ||||
-rw-r--r-- | gold/Makefile.in | 15 | ||||
-rw-r--r-- | gold/archive.cc | 34 | ||||
-rw-r--r-- | gold/archive.h | 17 | ||||
-rw-r--r-- | gold/common.cc | 32 | ||||
-rw-r--r-- | gold/common.h | 7 | ||||
-rw-r--r-- | gold/copy-relocs.cc | 2 | ||||
-rw-r--r-- | gold/ehframe.h | 12 | ||||
-rw-r--r-- | gold/gold.cc | 26 | ||||
-rw-r--r-- | gold/gold.h | 7 | ||||
-rw-r--r-- | gold/i386.cc | 7 | ||||
-rw-r--r-- | gold/layout.cc | 53 | ||||
-rw-r--r-- | gold/layout.h | 11 | ||||
-rw-r--r-- | gold/main.cc | 19 | ||||
-rw-r--r-- | gold/mapfile.cc | 405 | ||||
-rw-r--r-- | gold/mapfile.h | 113 | ||||
-rw-r--r-- | gold/merge.h | 10 | ||||
-rw-r--r-- | gold/object.h | 6 | ||||
-rw-r--r-- | gold/options.cc | 7 | ||||
-rw-r--r-- | gold/options.h | 5 | ||||
-rw-r--r-- | gold/output.cc | 58 | ||||
-rw-r--r-- | gold/output.h | 155 | ||||
-rw-r--r-- | gold/readsyms.cc | 14 | ||||
-rw-r--r-- | gold/readsyms.h | 28 | ||||
-rw-r--r-- | gold/script-sections.cc | 7 | ||||
-rw-r--r-- | gold/script.cc | 4 | ||||
-rw-r--r-- | gold/script.h | 3 | ||||
-rw-r--r-- | gold/sparc.cc | 5 | ||||
-rw-r--r-- | gold/symtab.h | 7 | ||||
-rw-r--r-- | gold/x86_64.cc | 7 |
31 files changed, 1081 insertions, 96 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog index bd4db9d..c8843ce 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,102 @@ +2008-05-21 Ian Lance Taylor <iant@google.com> + + * mapfile.cc: New file. + * mapfile.h: New file. + * options.h (class General_options): Add -M/--print-map and -Map. + * options.cc (General_options::finalize): Make -M equivalent to + -Map -. + * main.cc: Include <cstdio> and "mapfile.h". + (main): Open mapfile if requested. + * gold.cc (class Middle_runner): Add mapfile_ field. Update + constructor. Change caller. + (queue_initial_tasks): Add mapfile parameter. Change caller. + (queue_middle_tasks): Likewise. + * gold.h (queue_initial_tasks, queue_middle_tasks): Update + declarations. + * archive.cc: Include "mapfile.h". + (Archive::add_symbols): Add mapfile parameter. Change all + callers. Pass mapfile, symbol, and reason to include_member. + (Archive::include_all_members): Add mapfile parameter. Change all + callers. + (Archive::include_member): Add mapfile, sym, and why parameters. + Change all callers. Report inclusion to map file. + * archive.h: Include "fileread.h". + (class Archive): Update declarations. + (Archive::file): New const method. + (class Add_archive_symbols): Add mapfile_ field. Update + constructor. Change all callers. + * readsyms.h (class Read_symbols): Likewise. + (class Finish_group): Likewise. + (class Read_script): Likewise. + * common.cc: Include "mapfile.h". + (Symbol_table::allocate_commons): Add mapfile parameter. Change + all callers. + (Symbol_table::do_allocate_commons): Likewise. + (Symbol_table::do_allocate_commons_list): Likewise. Report common + symbol allocation to mapfile. + * common.h (class Allocate_commons_task): Add mapfile_ field. + Update constructor. Change all callers. + * symtab.h (class Symbol_table): Update declarations. + * layout.cc: Include "mapfile.h". + (Layout_task_runner::run): Print information to mapfile. + (Layout::create_gold_note): Change Output_data_fixed_space to + Output_data_zero_fill. + (Layout::create_build_id): Likewise. + (Layout::print_to_mapfile): New function. + * layout.h (class Layout_task_runner): Add mapfile_ field. Update + constructor. Change caller. + (class Layout): Declare print_to_mapfile. + * output.cc (Output_section::Input_section::print_to_mapfile): New + function. + (Output_section::add_input_section): If producing a map, always + add to input_sections_ list. + (Output_section::do_print_to_mapfile): New function. + (Output_segment::print_sections_to_mapfile): New function. + (Output_segment::print_section_list_to_mapfile): New function. + * output.h: Include "mapfile.h". + (Output_data::print_to_mapfile): New function. + (Output_data::do_print_to_mapfile): New virtual function. + (Output_segment_headers::do_print_to_mapfile): New function. + (Output_file_header::do_print_to_mapfile): New function. + (Output_data_const::do_print_to_mapfile): New function. + (class Output_data_const_buffer): Add map_name_ field. Update + constructor. Change all callers. Add do_print_to_mapfile + function. + (class Output_data_fixed_space): Likewise. + (class Output_data_space): Likewise. + (class Output_data_zero_fill): New class. + (Output_data_strtab::do_print_to_mapfile): New function. + (Output_data_reloc_base::do_print_to_mapfile): New function. + (Output_relocatable_relocs::do_print_to_mapfile): New function. + (Output_data_group::do_print_to_mapfile): New function. + (Output_data_got::do_print_to_mapfile): New function. + (Output_data_dynamic::do_print_to_mapfile): New function. + (Output_symtab_xindex::do_print_to_mapfile): New function. + (class Output_section): Declare do_print_to_mapflie. Declare + print_to_mapfile in Input_section. + (class Output_segment): Declare new functions. + * object.h (Sized_relobj::symbol_count): New function. + * script-sections.cc + (Output_section_element_dot_assignment::set_section_addresses): + Change Output_data_fixed_space to Output_data_zero_fill. + (Output_data_expression::do_print_to_mapfile): New function. + * script.cc (read_input_script): Add mapfile parameter. Change + all callers. + * script.h (read_input_script): Update declaration. + * ehframe.h (Eh_frame_hdr::do_print_to_mapfile): New function. + (Eh_frame::do_print_to_mapfile): New function. + * merge.h (Output_merge_data::do_print_to_mapfile): New function. + (Output_merge_string::do_print_to_mapfile): New function. + * i386.cc (Output_data_plt_i386::do_print_to_mapfile): New + function. + * sparc.cc (Output_data_plt_sparc::do_print_to_mapfile): New + function. + * x86_64.cc (Output_data_plt_x86_64::do_print_to_mapfile): New + function. + * Makefile.am (CCFILES): Add mapfile.cc. + (HFILES): Add mapfile.h. + * Makefile.in: Rebuild. + 2008-05-19 Ian Lance Taylor <iant@google.com> * options.h (class General_options): Add -z relro. diff --git a/gold/Makefile.am b/gold/Makefile.am index 020fd95..14c3c4b 100644 --- a/gold/Makefile.am +++ b/gold/Makefile.am @@ -45,6 +45,7 @@ CCFILES = \ gold.cc \ gold-threads.cc \ layout.cc \ + mapfile.cc \ merge.cc \ object.cc \ options.cc \ @@ -78,6 +79,7 @@ HFILES = \ gold.h \ gold-threads.h \ layout.h \ + mapfile.h \ merge.h \ object.h \ options.h \ diff --git a/gold/Makefile.in b/gold/Makefile.in index cc1a9e4..5781ebc 100644 --- a/gold/Makefile.in +++ b/gold/Makefile.in @@ -79,12 +79,12 @@ am__objects_1 = archive.$(OBJEXT) binary.$(OBJEXT) common.$(OBJEXT) \ defstd.$(OBJEXT) dirsearch.$(OBJEXT) dynobj.$(OBJEXT) \ dwarf_reader.$(OBJEXT) ehframe.$(OBJEXT) errors.$(OBJEXT) \ expression.$(OBJEXT) fileread.$(OBJEXT) gold.$(OBJEXT) \ - gold-threads.$(OBJEXT) layout.$(OBJEXT) merge.$(OBJEXT) \ - object.$(OBJEXT) options.$(OBJEXT) output.$(OBJEXT) \ - parameters.$(OBJEXT) readsyms.$(OBJEXT) reloc.$(OBJEXT) \ - resolve.$(OBJEXT) script-sections.$(OBJEXT) script.$(OBJEXT) \ - stringpool.$(OBJEXT) symtab.$(OBJEXT) target-select.$(OBJEXT) \ - version.$(OBJEXT) workqueue.$(OBJEXT) \ + gold-threads.$(OBJEXT) layout.$(OBJEXT) mapfile.$(OBJEXT) \ + merge.$(OBJEXT) object.$(OBJEXT) options.$(OBJEXT) \ + output.$(OBJEXT) parameters.$(OBJEXT) readsyms.$(OBJEXT) \ + reloc.$(OBJEXT) resolve.$(OBJEXT) script-sections.$(OBJEXT) \ + script.$(OBJEXT) stringpool.$(OBJEXT) symtab.$(OBJEXT) \ + target-select.$(OBJEXT) version.$(OBJEXT) workqueue.$(OBJEXT) \ workqueue-threads.$(OBJEXT) am__objects_2 = am__objects_3 = yyscript.$(OBJEXT) @@ -325,6 +325,7 @@ CCFILES = \ gold.cc \ gold-threads.cc \ layout.cc \ + mapfile.cc \ merge.cc \ object.cc \ options.cc \ @@ -358,6 +359,7 @@ HFILES = \ gold.h \ gold-threads.h \ layout.h \ + mapfile.h \ merge.h \ object.h \ options.h \ @@ -531,6 +533,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/i386.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/layout.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mapfile.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/merge.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/object.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/options.Po@am__quote@ diff --git a/gold/archive.cc b/gold/archive.cc index 1e16de9..0ff8aee 100644 --- a/gold/archive.cc +++ b/gold/archive.cc @@ -31,6 +31,7 @@ #include "elfcpp.h" #include "options.h" +#include "mapfile.h" #include "fileread.h" #include "readsyms.h" #include "symtab.h" @@ -286,10 +287,11 @@ Archive::interpret_header(const Archive_header* hdr, off_t off, void Archive::add_symbols(Symbol_table* symtab, Layout* layout, - Input_objects* input_objects) + Input_objects* input_objects, Mapfile* mapfile) { if (this->input_file_->options().whole_archive()) - return this->include_all_members(symtab, layout, input_objects); + return this->include_all_members(symtab, layout, input_objects, + mapfile); const size_t armap_size = this->armap_.size(); @@ -343,8 +345,16 @@ Archive::add_symbols(Symbol_table* symtab, Layout* layout, last_seen_offset = this->armap_[i].file_offset; this->seen_offsets_.insert(last_seen_offset); this->armap_checked_[i] = true; + + std::string why; + if (sym == NULL) + { + why = "-u "; + why += sym_name; + } this->include_member(symtab, layout, input_objects, - last_seen_offset); + last_seen_offset, mapfile, sym, why.c_str()); + added_new_object = true; } } @@ -355,7 +365,7 @@ Archive::add_symbols(Symbol_table* symtab, Layout* layout, void Archive::include_all_members(Symbol_table* symtab, Layout* layout, - Input_objects* input_objects) + Input_objects* input_objects, Mapfile* mapfile) { off_t off = sarmag; off_t filesize = this->input_file_->file().filesize(); @@ -385,7 +395,8 @@ Archive::include_all_members(Symbol_table* symtab, Layout* layout, // Extended name table. } else - this->include_member(symtab, layout, input_objects, off); + this->include_member(symtab, layout, input_objects, off, + mapfile, NULL, "--whole-archive"); off += sizeof(Archive_header); if (!this->is_thin_archive_) @@ -396,16 +407,20 @@ Archive::include_all_members(Symbol_table* symtab, Layout* layout, } // Include an archive member in the link. OFF is the file offset of -// the member header. +// the member header. WHY is the reason we are including this member. void Archive::include_member(Symbol_table* symtab, Layout* layout, - Input_objects* input_objects, off_t off) + Input_objects* input_objects, off_t off, + Mapfile* mapfile, Symbol* sym, const char* why) { std::string n; off_t nested_off; this->read_header(off, false, &n, &nested_off); + if (mapfile != NULL) + mapfile->report_include_archive_member(this, n, sym, why); + Input_file* input_file; off_t memoff; @@ -451,7 +466,8 @@ Archive::include_member(Symbol_table* symtab, Layout* layout, this->nested_archives_.insert(std::make_pair(n, arch)); gold_assert(ins.second); } - arch->include_member(symtab, layout, input_objects, nested_off); + arch->include_member(symtab, layout, input_objects, nested_off, + NULL, NULL, NULL); return; } // This is an external member of a thin archive. Open the @@ -551,7 +567,7 @@ void Add_archive_symbols::run(Workqueue*) { this->archive_->add_symbols(this->symtab_, this->layout_, - this->input_objects_); + this->input_objects_, this->mapfile_); this->archive_->unlock_nested_archives(); diff --git a/gold/archive.h b/gold/archive.h index 818bd60..c8b05e4 100644 --- a/gold/archive.h +++ b/gold/archive.h @@ -26,6 +26,7 @@ #include <string> #include <vector> +#include "fileread.h" #include "workqueue.h" namespace gold @@ -75,6 +76,10 @@ class Archive file() { return this->input_file_->file(); } + const File_read& + file() const + { return this->input_file_->file(); } + // Lock the underlying file. void lock(const Task* t) @@ -112,7 +117,7 @@ class Archive // Select members from the archive as needed and add them to the // link. void - add_symbols(Symbol_table*, Layout*, Input_objects*); + add_symbols(Symbol_table*, Layout*, Input_objects*, Mapfile*); private: Archive(const Archive&); @@ -143,11 +148,12 @@ class Archive // Include all the archive members in the link. void - include_all_members(Symbol_table*, Layout*, Input_objects*); + include_all_members(Symbol_table*, Layout*, Input_objects*, Mapfile*); // Include an archive member in the link. void - include_member(Symbol_table*, Layout*, Input_objects*, off_t off); + include_member(Symbol_table*, Layout*, Input_objects*, off_t off, + Mapfile*, Symbol*, const char* why); // An entry in the archive map of symbols to object files. struct Armap_entry @@ -201,12 +207,12 @@ class Add_archive_symbols : public Task { public: Add_archive_symbols(Symbol_table* symtab, Layout* layout, - Input_objects* input_objects, + Input_objects* input_objects, Mapfile* mapfile, Archive* archive, Input_group* input_group, Task_token* this_blocker, Task_token* next_blocker) : symtab_(symtab), layout_(layout), input_objects_(input_objects), - archive_(archive), input_group_(input_group), + mapfile_(mapfile), archive_(archive), input_group_(input_group), this_blocker_(this_blocker), next_blocker_(next_blocker) { } @@ -235,6 +241,7 @@ class Add_archive_symbols : public Task Symbol_table* symtab_; Layout* layout_; Input_objects* input_objects_; + Mapfile* mapfile_; Archive* archive_; Input_group* input_group_; Task_token* this_blocker_; diff --git a/gold/common.cc b/gold/common.cc index 6789d5d..632a20b 100644 --- a/gold/common.cc +++ b/gold/common.cc @@ -25,6 +25,7 @@ #include <algorithm> #include "workqueue.h" +#include "mapfile.h" #include "layout.h" #include "output.h" #include "symtab.h" @@ -60,7 +61,7 @@ Allocate_commons_task::locks(Task_locker* tl) void Allocate_commons_task::run(Workqueue*) { - this->symtab_->allocate_commons(this->layout_); + this->symtab_->allocate_commons(this->layout_, this->mapfile_); } // This class is used to sort the common symbol by size. We put the @@ -117,12 +118,12 @@ Sort_commons<size>::operator()(const Symbol* pa, const Symbol* pb) const // Allocate the common symbols. void -Symbol_table::allocate_commons(Layout* layout) +Symbol_table::allocate_commons(Layout* layout, Mapfile* mapfile) { if (parameters->target().get_size() == 32) { #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG) - this->do_allocate_commons<32>(layout); + this->do_allocate_commons<32>(layout, mapfile); #else gold_unreachable(); #endif @@ -130,7 +131,7 @@ Symbol_table::allocate_commons(Layout* layout) else if (parameters->target().get_size() == 64) { #if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG) - this->do_allocate_commons<64>(layout); + this->do_allocate_commons<64>(layout, mapfile); #else gold_unreachable(); #endif @@ -143,10 +144,12 @@ Symbol_table::allocate_commons(Layout* layout) template<int size> void -Symbol_table::do_allocate_commons(Layout* layout) +Symbol_table::do_allocate_commons(Layout* layout, Mapfile* mapfile) { - this->do_allocate_commons_list<size>(layout, false, &this->commons_); - this->do_allocate_commons_list<size>(layout, true, &this->tls_commons_); + this->do_allocate_commons_list<size>(layout, false, &this->commons_, + mapfile); + this->do_allocate_commons_list<size>(layout, true, &this->tls_commons_, + mapfile); } // Allocate the common symbols in a list. IS_TLS indicates whether @@ -155,7 +158,8 @@ Symbol_table::do_allocate_commons(Layout* layout) template<int size> void Symbol_table::do_allocate_commons_list(Layout* layout, bool is_tls, - Commons_type* commons) + Commons_type* commons, + Mapfile* mapfile) { typedef typename Sized_symbol<size>::Value_type Value_type; typedef typename Sized_symbol<size>::Size_type Size_type; @@ -195,7 +199,10 @@ Symbol_table::do_allocate_commons_list(Layout* layout, bool is_tls, // Place them in a newly allocated BSS section. - Output_data_space *poc = new Output_data_space(addralign); + Output_data_space *poc = new Output_data_space(addralign, + (is_tls + ? "** tls common" + : "** common")); const char* name = ".bss"; elfcpp::Elf_Xword flags = elfcpp::SHF_WRITE | elfcpp::SHF_ALLOC; @@ -217,6 +224,13 @@ Symbol_table::do_allocate_commons_list(Layout* layout, bool is_tls, if (sym == NULL) break; Sized_symbol<size>* ssym = this->get_sized_symbol<size>(sym); + + // Record the symbol in the map file now, before we change its + // value. Pass the size in separately so that we don't have to + // templatize the map code, which is not performance sensitive. + if (mapfile != NULL) + mapfile->report_allocate_common(sym, ssym->symsize()); + off = align_address(off, ssym->value()); ssym->allocate_common(poc, off); off += ssym->symsize(); diff --git a/gold/common.h b/gold/common.h index 6c281c9..9653604 100644 --- a/gold/common.h +++ b/gold/common.h @@ -35,10 +35,10 @@ class Symbol_table; class Allocate_commons_task : public Task { public: - Allocate_commons_task(Symbol_table* symtab, Layout* layout, + Allocate_commons_task(Symbol_table* symtab, Layout* layout, Mapfile* mapfile, Task_token* symtab_lock, Task_token* blocker) - : symtab_(symtab), layout_(layout), symtab_lock_(symtab_lock), - blocker_(blocker) + : symtab_(symtab), layout_(layout), mapfile_(mapfile), + symtab_lock_(symtab_lock), blocker_(blocker) { } // The standard Task methods. @@ -59,6 +59,7 @@ class Allocate_commons_task : public Task private: Symbol_table* symtab_; Layout* layout_; + Mapfile* mapfile_; Task_token* symtab_lock_; Task_token* blocker_; }; diff --git a/gold/copy-relocs.cc b/gold/copy-relocs.cc index 3df50c8..c6cd994 100644 --- a/gold/copy-relocs.cc +++ b/gold/copy-relocs.cc @@ -130,7 +130,7 @@ Copy_relocs<sh_type, size, big_endian>::emit_copy_reloc( if (this->dynbss_ == NULL) { - this->dynbss_ = new Output_data_space(addralign); + this->dynbss_ = new Output_data_space(addralign, "** dynbss"); layout->add_output_section_data(".bss", elfcpp::SHT_NOBITS, elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE, diff --git a/gold/ehframe.h b/gold/ehframe.h index 47e3e4c..4726ffc 100644 --- a/gold/ehframe.h +++ b/gold/ehframe.h @@ -67,6 +67,7 @@ class Eh_frame_hdr : public Output_section_data this->fde_offsets_.push_back(std::make_pair(fde_offset, fde_encoding)); } + protected: // Set the final data size. void set_final_data_size(); @@ -75,6 +76,11 @@ class Eh_frame_hdr : public Output_section_data void do_write(Output_file*); + // Write to a map file. + void + do_print_to_mapfile(Mapfile* mapfile) const + { mapfile->print_output_data(this, _("** eh_frame_hdr")); } + private: // Write the data to the file with the right endianness. template<int size, bool big_endian> @@ -322,6 +328,7 @@ class Eh_frame : public Output_section_data unsigned int fde_count() const; + protected: // Set the final data size. void set_final_data_size(); @@ -340,6 +347,11 @@ class Eh_frame : public Output_section_data void do_write(Output_file*); + // Write to a map file. + void + do_print_to_mapfile(Mapfile* mapfile) const + { mapfile->print_output_data(this, _("** eh_frame")); } + private: // The comparison routine for the CIE map. struct Cie_less diff --git a/gold/gold.cc b/gold/gold.cc index 267c4d1..42c6248 100644 --- a/gold/gold.cc +++ b/gold/gold.cc @@ -94,9 +94,9 @@ class Middle_runner : public Task_function_runner Middle_runner(const General_options& options, const Input_objects* input_objects, Symbol_table* symtab, - Layout* layout) + Layout* layout, Mapfile* mapfile) : options_(options), input_objects_(input_objects), symtab_(symtab), - layout_(layout) + layout_(layout), mapfile_(mapfile) { } void @@ -107,13 +107,14 @@ class Middle_runner : public Task_function_runner const Input_objects* input_objects_; Symbol_table* symtab_; Layout* layout_; + Mapfile* mapfile_; }; void Middle_runner::run(Workqueue* workqueue, const Task* task) { queue_middle_tasks(this->options_, task, this->input_objects_, this->symtab_, - this->layout_, workqueue); + this->layout_, workqueue, this->mapfile_); } // Queue up the initial set of tasks for this link job. @@ -123,7 +124,7 @@ queue_initial_tasks(const General_options& options, Dirsearch& search_path, const Command_line& cmdline, Workqueue* workqueue, Input_objects* input_objects, - Symbol_table* symtab, Layout* layout) + Symbol_table* symtab, Layout* layout, Mapfile* mapfile) { if (cmdline.begin() == cmdline.end()) gold_fatal(_("no input files")); @@ -145,15 +146,16 @@ queue_initial_tasks(const General_options& options, Task_token* next_blocker = new Task_token(true); next_blocker->add_blocker(); workqueue->queue(new Read_symbols(options, input_objects, symtab, layout, - &search_path, &*p, NULL, this_blocker, - next_blocker)); + &search_path, mapfile, &*p, NULL, + this_blocker, next_blocker)); this_blocker = next_blocker; } workqueue->queue(new Task_function(new Middle_runner(options, input_objects, symtab, - layout), + layout, + mapfile), this_blocker, "Task_function Middle_runner")); } @@ -168,7 +170,8 @@ queue_middle_tasks(const General_options& options, const Input_objects* input_objects, Symbol_table* symtab, Layout* layout, - Workqueue* workqueue) + Workqueue* workqueue, + Mapfile* mapfile) { // We have to support the case of not seeing any input objects, and // generate an empty file. Existing builds depend on being able to @@ -272,8 +275,8 @@ queue_middle_tasks(const General_options& options, if (parameters->options().define_common()) { blocker->add_blocker(); - workqueue->queue(new Allocate_commons_task(symtab, layout, symtab_lock, - blocker)); + workqueue->queue(new Allocate_commons_task(symtab, layout, mapfile, + symtab_lock, blocker)); } // When all those tasks are complete, we can start laying out the @@ -284,7 +287,8 @@ queue_middle_tasks(const General_options& options, input_objects, symtab, target, - layout), + layout, + mapfile), blocker, "Task_function Layout_task_runner")); } diff --git a/gold/gold.h b/gold/gold.h index 62c014e..03e73d3 100644 --- a/gold/gold.h +++ b/gold/gold.h @@ -115,6 +115,7 @@ class Command_line; class Input_argument_list; class Dirsearch; class Input_objects; +class Mapfile; class Symbol; class Symbol_table; class Layout; @@ -241,7 +242,8 @@ queue_initial_tasks(const General_options&, Workqueue*, Input_objects*, Symbol_table*, - Layout*); + Layout*, + Mapfile*); // Queue up the middle set of tasks. extern void @@ -250,7 +252,8 @@ queue_middle_tasks(const General_options&, const Input_objects*, Symbol_table*, Layout*, - Workqueue*); + Workqueue*, + Mapfile*); // Queue up the final set of tasks. extern void diff --git a/gold/i386.cc b/gold/i386.cc index 4785fa6..948b5d6 100644 --- a/gold/i386.cc +++ b/gold/i386.cc @@ -437,7 +437,7 @@ Target_i386::got_section(Symbol_table* symtab, Layout* layout) // create another set of data in the .got section. Note that we // always create a PLT if we create a GOT, although the PLT // might be empty. - this->got_plt_ = new Output_data_space(4); + this->got_plt_ = new Output_data_space(4, "** GOT PLT"); os = layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS, (elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE), @@ -496,6 +496,11 @@ class Output_data_plt_i386 : public Output_section_data void do_adjust_output_section(Output_section* os); + // Write to a map file. + void + do_print_to_mapfile(Mapfile* mapfile) const + { mapfile->print_output_data(this, _("** PLT")); } + private: // The size of an entry in the PLT. static const int plt_entry_size = 16; diff --git a/gold/layout.cc b/gold/layout.cc index eae6679..a4003d5 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -35,6 +35,7 @@ #include "parameters.h" #include "options.h" +#include "mapfile.h" #include "script.h" #include "script-sections.h" #include "output.h" @@ -63,6 +64,13 @@ Layout_task_runner::run(Workqueue* workqueue, const Task* task) // Now we know the final size of the output file and we know where // each piece of information goes. + + if (this->mapfile_ != NULL) + { + this->mapfile_->print_discarded_sections(this->input_objects_); + this->layout_->print_to_mapfile(this->mapfile_); + } + Output_file* of = new Output_file(parameters->options().output_file_name()); if (this->options_.oformat_enum() != General_options::OBJECT_FORMAT_ELF) of->set_is_temporary(); @@ -1323,7 +1331,8 @@ Layout::create_note(const char* name, int note_type, size_t descsz, elfcpp::SHT_NOTE, flags); Output_section_data* posd = new Output_data_const_buffer(buffer, notehdrsz, - size / 8); + size / 8, + "** note header"); os->add_output_section_data(posd); *trailing_padding = aligned_descsz - descsz; @@ -1351,7 +1360,7 @@ Layout::create_gold_note() if (trailing_padding > 0) { - posd = new Output_data_fixed_space(trailing_padding, 0); + posd = new Output_data_zero_fill(trailing_padding, 0); os->add_output_section_data(posd); } } @@ -1488,7 +1497,7 @@ Layout::create_build_id() if (trailing_padding != 0) { - posd = new Output_data_fixed_space(trailing_padding, 0); + posd = new Output_data_zero_fill(trailing_padding, 0); os->add_output_section_data(posd); } } @@ -1497,7 +1506,7 @@ Layout::create_build_id() // We need to compute a checksum after we have completed the // link. gold_assert(trailing_padding == 0); - this->build_id_note_ = new Output_data_fixed_space(descsz, 4); + this->build_id_note_ = new Output_data_zero_fill(descsz, 4); os->add_output_section_data(this->build_id_note_); os->set_after_input_sections(); } @@ -2049,7 +2058,8 @@ Layout::create_symtab_sections(const Input_objects* input_objects, this->symtab_section_ = osymtab; Output_section_data* pos = new Output_data_fixed_space(off - startoff, - align); + align, + "** symtab"); osymtab->add_output_section_data(pos); // We generate a .symtab_shndx section if we have more than @@ -2230,7 +2240,8 @@ Layout::create_dynamic_symtab(const Input_objects* input_objects, false); Output_section_data* odata = new Output_data_fixed_space(index * symsize, - align); + align, + "** dynsym"); dynsym->add_output_section_data(odata); dynsym->set_info(local_symcount); @@ -2309,7 +2320,8 @@ Layout::create_dynamic_symtab(const Input_objects* input_objects, Output_section_data* hashdata = new Output_data_const_buffer(phash, hashlen, - align); + align, + "** hash"); hashsec->add_output_section_data(hashdata); hashsec->set_link_section(dynsym); @@ -2333,7 +2345,8 @@ Layout::create_dynamic_symtab(const Input_objects* input_objects, Output_section_data* hashdata = new Output_data_const_buffer(phash, hashlen, - align); + align, + "** hash"); hashsec->add_output_section_data(hashdata); hashsec->set_link_section(dynsym); @@ -2435,7 +2448,8 @@ Layout::sized_create_version_sections( dynamic_symbols, &vbuf, &vsize); - Output_section_data* vdata = new Output_data_const_buffer(vbuf, vsize, 2); + Output_section_data* vdata = new Output_data_const_buffer(vbuf, vsize, 2, + "** versions"); vsec->add_output_section_data(vdata); vsec->set_entsize(2); @@ -2458,9 +2472,8 @@ Layout::sized_create_version_sections( versions->def_section_contents<size, big_endian>(&this->dynpool_, &vdbuf, &vdsize, &vdentries); - Output_section_data* vddata = new Output_data_const_buffer(vdbuf, - vdsize, - 4); + Output_section_data* vddata = + new Output_data_const_buffer(vdbuf, vdsize, 4, "** version defs"); vdsec->add_output_section_data(vddata); vdsec->set_link_section(dynstr); @@ -2485,9 +2498,8 @@ Layout::sized_create_version_sections( &vnbuf, &vnsize, &vnentries); - Output_section_data* vndata = new Output_data_const_buffer(vnbuf, - vnsize, - 4); + Output_section_data* vndata = + new Output_data_const_buffer(vnbuf, vnsize, 4, "** version refs"); vnsec->add_output_section_data(vndata); vnsec->set_link_section(dynstr); @@ -3086,6 +3098,17 @@ Layout::write_binary(Output_file* in) const out.close(); } +// Print the output sections to the map file. + +void +Layout::print_to_mapfile(Mapfile* mapfile) const +{ + for (Segment_list::const_iterator p = this->segment_list_.begin(); + p != this->segment_list_.end(); + ++p) + (*p)->print_sections_to_mapfile(mapfile); +} + // Print statistical information to stderr. This is used for --stats. void diff --git a/gold/layout.h b/gold/layout.h index ede2604..1c71d47 100644 --- a/gold/layout.h +++ b/gold/layout.h @@ -40,6 +40,7 @@ namespace gold class General_options; class Input_objects; +class Mapfile; class Symbol_table; class Output_section_data; class Output_section; @@ -64,9 +65,10 @@ class Layout_task_runner : public Task_function_runner const Input_objects* input_objects, Symbol_table* symtab, Target* target, - Layout* layout) + Layout* layout, + Mapfile* mapfile) : options_(options), input_objects_(input_objects), symtab_(symtab), - target_(target), layout_(layout) + target_(target), layout_(layout), mapfile_(mapfile) { } // Run the operation. @@ -82,6 +84,7 @@ class Layout_task_runner : public Task_function_runner Symbol_table* symtab_; Target* target_; Layout* layout_; + Mapfile* mapfile_; }; // This class handles the details of laying out input sections. @@ -334,6 +337,10 @@ class Layout void write_binary(Output_file* in) const; + // Print output sections to the map file. + void + print_to_mapfile(Mapfile*) const; + // Dump statistical information to stderr. void print_stats() const; diff --git a/gold/main.cc b/gold/main.cc index c785da2..3577283 100644 --- a/gold/main.cc +++ b/gold/main.cc @@ -22,6 +22,7 @@ #include "gold.h" +#include <cstdio> #include <cstring> #ifdef HAVE_MALLINFO @@ -34,6 +35,7 @@ #include "options.h" #include "parameters.h" #include "errors.h" +#include "mapfile.h" #include "dirsearch.h" #include "workqueue.h" #include "object.h" @@ -165,6 +167,18 @@ main(int argc, char** argv) write_debug_script(command_line.options().output_file_name(), program_name, args.c_str()); + // If the user asked for a map file, open it. + Mapfile* mapfile = NULL; + if (command_line.options().user_set_Map()) + { + mapfile = new Mapfile(); + if (!mapfile->open(command_line.options().Map())) + { + delete mapfile; + mapfile = NULL; + } + } + // The GNU linker ignores version scripts when generating // relocatable output. If we are not compatible, then we break the // Linux kernel build, which uses a linker script with -r which must @@ -198,7 +212,7 @@ main(int argc, char** argv) // Queue up the first set of tasks. queue_initial_tasks(command_line.options(), search_path, command_line, &workqueue, &input_objects, - &symtab, &layout); + &symtab, &layout, mapfile); // Run the main task processing loop. workqueue.process(0); @@ -220,6 +234,9 @@ main(int argc, char** argv) layout.print_stats(); } + if (mapfile != NULL) + mapfile->close(); + if (parameters->options().fatal_warnings() && errors.warning_count() > 0 && errors.error_count() == 0) diff --git a/gold/mapfile.cc b/gold/mapfile.cc new file mode 100644 index 0000000..e053419 --- /dev/null +++ b/gold/mapfile.cc @@ -0,0 +1,405 @@ +// mapfile.cc -- map file generation for gold + +// Copyright 2008 Free Software Foundation, Inc. +// Written by Ian Lance Taylor <iant@google.com>. + +// This file is part of gold. + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, +// MA 02110-1301, USA. + +#include "gold.h" + +#include <cerrno> +#include <cstdio> +#include <cstring> + +#include "archive.h" +#include "symtab.h" +#include "output.h" +#include "mapfile.h" + +// This file holds the code for printing information to the map file. +// In general we try to produce pretty much the same format as GNU ld. + +namespace gold +{ + +// Mapfile constructor. + +Mapfile::Mapfile() + : map_file_(NULL), + printed_archive_header_(false), + printed_common_header_(false), + printed_memory_map_header_(false) +{ +} + +// Mapfile destructor. + +Mapfile::~Mapfile() +{ + if (this->map_file_ != NULL) + this->close(); +} + +// Open the map file. + +bool +Mapfile::open(const char* map_filename) +{ + if (strcmp(map_filename, "-") == 0) + this->map_file_ = stdout; + else + { + this->map_file_ = ::fopen(map_filename, "w"); + if (this->map_file_ == NULL) + { + gold_error(_("cannot open map file %s: %s"), map_filename, + strerror(errno)); + return false; + } + } + return true; +} + +// Close the map file. + +void +Mapfile::close() +{ + if (fclose(this->map_file_) != 0) + gold_error(_("cannot close map file: %s"), strerror(errno)); + this->map_file_ = NULL; +} + +// Advance to a column. + +void +Mapfile::advance_to_column(size_t from, size_t to) +{ + if (from >= to - 1) + { + putc('\n', this->map_file_); + from = 0; + } + while (from < to) + { + putc(' ', this->map_file_); + ++from; + } +} + +// Report about including a member from an archive. + +void +Mapfile::report_include_archive_member(const Archive* archive, + const std::string& member_name, + const Symbol* sym, const char* why) +{ + // We print a header before the list of archive members, mainly for + // GNU ld compatibility. + if (!this->printed_archive_header_) + { + fprintf(this->map_file_, + _("Archive member included because of file (symbol)\n\n")); + this->printed_archive_header_ = true; + } + + fprintf(this->map_file_, "%s(%s)", archive->file().filename().c_str(), + member_name.c_str()); + + size_t len = (archive->file().filename().length() + + member_name.length() + + 2); + this->advance_to_column(len, 30); + + if (sym == NULL) + fprintf(this->map_file_, "%s", why); + else + { + switch (sym->source()) + { + case Symbol::FROM_OBJECT: + fprintf(this->map_file_, "%s", sym->object()->name().c_str()); + break; + + case Symbol::IS_UNDEFINED: + fprintf(this->map_file_, "-u"); + break; + + default: + case Symbol::IN_OUTPUT_DATA: + case Symbol::IN_OUTPUT_SEGMENT: + case Symbol::IS_CONSTANT: + // We should only see an undefined symbol here. + gold_unreachable(); + } + + fprintf(this->map_file_, " (%s)", sym->name()); + } + + putc('\n', this->map_file_); +} + +// Report allocating a common symbol. + +void +Mapfile::report_allocate_common(const Symbol* sym, uint64_t symsize) +{ + if (!this->printed_common_header_) + { + fprintf(this->map_file_, _("\nAllocating common symbols\n")); + fprintf(this->map_file_, + _("Common symbol size file\n\n")); + this->printed_common_header_ = true; + } + + std::string demangled_name = sym->demangled_name(); + fprintf(this->map_file_, "%s", demangled_name.c_str()); + + this->advance_to_column(demangled_name.length(), 20); + + char buf[50]; + snprintf(buf, sizeof buf, "0x%llx", static_cast<unsigned long long>(symsize)); + fprintf(this->map_file_, "%s", buf); + + size_t len = strlen(buf); + while (len < 18) + { + putc(' ', this->map_file_); + ++len; + } + + fprintf(this->map_file_, "%s\n", sym->object()->name().c_str()); +} + +// The space we make for a section name. + +const size_t Mapfile::section_name_map_length = 16; + +// Print the memory map header if necessary. + +void +Mapfile::print_memory_map_header() +{ + if (!this->printed_memory_map_header_) + { + fprintf(this->map_file_, _("\nMemory map\n\n")); + this->printed_memory_map_header_ = true; + } +} + +// Print the symbols associated with an input section. + +template<int size, bool big_endian> +void +Mapfile::print_input_section_symbols( + const Sized_relobj<size, big_endian>* relobj, + unsigned int shndx) +{ + unsigned int symcount = relobj->symbol_count(); + for (unsigned int i = relobj->local_symbol_count(); i < symcount; ++i) + { + const Symbol* sym = relobj->global_symbol(i); + bool is_ordinary; + if (sym != NULL + && sym->source() == Symbol::FROM_OBJECT + && sym->object() == relobj + && sym->shndx(&is_ordinary) == shndx + && is_ordinary + && sym->is_defined()) + { + for (size_t i = 0; i < Mapfile::section_name_map_length; ++i) + putc(' ', this->map_file_); + const Sized_symbol<size>* ssym = + static_cast<const Sized_symbol<size>*>(sym); + fprintf(this->map_file_, + "0x%0*llx %s\n", + size / 4, + static_cast<unsigned long long>(ssym->value()), + sym->demangled_name().c_str()); + } + } +} + +// Print an input section. + +void +Mapfile::print_input_section(Relobj* relobj, unsigned int shndx) +{ + putc(' ', this->map_file_); + + std::string name = relobj->section_name(shndx); + fprintf(this->map_file_, "%s", name.c_str()); + + this->advance_to_column(name.length() + 1, Mapfile::section_name_map_length); + + Output_section* os; + uint64_t addr; + if (!relobj->is_section_included(shndx)) + { + os = NULL; + addr = 0; + } + else + { + section_offset_type offset; + os = relobj->output_section(shndx, &offset); + if (offset == -1) + addr = ~0ULL; + else + addr = os->address() + offset; + } + + char sizebuf[50]; + snprintf(sizebuf, sizeof sizebuf, "0x%llx", + static_cast<unsigned long long>(relobj->section_size(shndx))); + + fprintf(this->map_file_, "0x%0*llx %10s %s\n", + parameters->target().get_size() / 4, + static_cast<unsigned long long>(addr), sizebuf, + relobj->name().c_str()); + + if (os != NULL) + { + switch (parameters->size_and_endianness()) + { +#ifdef HAVE_TARGET_32_LITTLE + case Parameters::TARGET_32_LITTLE: + { + const Sized_relobj<32, false>* sized_relobj = + static_cast<Sized_relobj<32, false>*>(relobj); + this->print_input_section_symbols(sized_relobj, shndx); + } + break; +#endif +#ifdef HAVE_TARGET_32_BIG + case Parameters::TARGET_32_BIG: + { + const Sized_relobj<32, true>* sized_relobj = + static_cast<Sized_relobj<32, true>*>(relobj); + this->print_input_section_symbols(sized_relobj, shndx); + } + break; +#endif +#ifdef HAVE_TARGET_64_LITTLE + case Parameters::TARGET_64_LITTLE: + { + const Sized_relobj<64, false>* sized_relobj = + static_cast<Sized_relobj<64, false>*>(relobj); + this->print_input_section_symbols(sized_relobj, shndx); + } + break; +#endif +#ifdef HAVE_TARGET_64_BIG + case Parameters::TARGET_64_BIG: + { + const Sized_relobj<64, true>* sized_relobj = + static_cast<Sized_relobj<64, true>*>(relobj); + this->print_input_section_symbols(sized_relobj, shndx); + } + break; +#endif + default: + gold_unreachable(); + } + } +} + +// Print an Output_section_data. This is printed to look like an +// input section. + +void +Mapfile::print_output_data(const Output_data* od, const char* name) +{ + this->print_memory_map_header(); + + putc(' ', this->map_file_); + + fprintf(this->map_file_, "%s", name); + + this->advance_to_column(strlen(name) + 1, Mapfile::section_name_map_length); + + char sizebuf[50]; + snprintf(sizebuf, sizeof sizebuf, "0x%llx", + static_cast<unsigned long long>(od->data_size())); + + fprintf(this->map_file_, "0x%0*llx %10s\n", + parameters->target().get_size() / 4, + static_cast<unsigned long long>(od->address()), + sizebuf); +} + +// Print the discarded input sections. + +void +Mapfile::print_discarded_sections(const Input_objects* input_objects) +{ + bool printed_header = false; + for (Input_objects::Relobj_iterator p = input_objects->relobj_begin(); + p != input_objects->relobj_end(); + ++p) + { + Relobj* relobj = *p; + unsigned int shnum = relobj->shnum(); + for (unsigned int i = 0; i < shnum; ++i) + { + unsigned int sh_type = relobj->section_type(i); + if ((sh_type == elfcpp::SHT_PROGBITS + || sh_type == elfcpp::SHT_NOBITS + || sh_type == elfcpp::SHT_GROUP) + && !relobj->is_section_included(i)) + { + if (!printed_header) + { + fprintf(this->map_file_, _("\nDiscarded input sections\n\n")); + printed_header = true; + } + + this->print_input_section(relobj, i); + } + } + } +} + +// Print an output section. + +void +Mapfile::print_output_section(const Output_section* os) +{ + this->print_memory_map_header(); + + fprintf(this->map_file_, "\n%s", os->name()); + + this->advance_to_column(strlen(os->name()), Mapfile::section_name_map_length); + + char sizebuf[50]; + snprintf(sizebuf, sizeof sizebuf, "0x%llx", + static_cast<unsigned long long>(os->data_size())); + + fprintf(this->map_file_, "0x%0*llx %10s", + parameters->target().get_size() / 4, + static_cast<unsigned long long>(os->address()), sizebuf); + + if (os->has_load_address()) + fprintf(this->map_file_, " load address 0x%-*llx", + parameters->target().get_size() / 4, + static_cast<unsigned long long>(os->load_address())); + + putc('\n', this->map_file_); +} + +} // End namespace gold. diff --git a/gold/mapfile.h b/gold/mapfile.h new file mode 100644 index 0000000..e2cf085 --- /dev/null +++ b/gold/mapfile.h @@ -0,0 +1,113 @@ +// mapfile.h -- map file generation for gold -*- C++ -*- + +// Copyright 2008 Free Software Foundation, Inc. +// Written by Ian Lance Taylor <iant@google.com>. + +// This file is part of gold. + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, +// MA 02110-1301, USA. + +#ifndef GOLD_MAP_H +#define GOLD_MAP_H + +#include <cstdio> +#include <string> + +namespace gold +{ + +class Archive; +class Symbol; +class Relobj; +template<int size, bool big_endian> +class Sized_relobj; +class Output_section; +class Output_data; + +// This class manages map file output. + +class Mapfile +{ + public: + Mapfile(); + + ~Mapfile(); + + // Open the map file. Return whether the open succeed. + bool + open(const char* map_filename); + + // Close the map file. + void + close(); + + // Report that we are including a member from an archive. This is + // called by the archive reading code. + void + report_include_archive_member(const Archive*, const std::string& member_name, + const Symbol* sym, const char* why); + + // Report allocating a common symbol. + void + report_allocate_common(const Symbol*, uint64_t symsize); + + // Print discarded input sections. + void + print_discarded_sections(const Input_objects*); + + // Print an output section. + void + print_output_section(const Output_section*); + + // Print an input section. + void + print_input_section(Relobj*, unsigned int shndx); + + // Print an Output_data. + void + print_output_data(const Output_data*, const char* name); + + private: + // The space we allow for a section name. + static const size_t section_name_map_length; + + // Advance to a column. + void + advance_to_column(size_t from, size_t to); + + // Print the memory map header. + void + print_memory_map_header(); + + // Print symbols for an input section. + template<int size, bool big_endian> + void + print_input_section_symbols(const Sized_relobj<size, big_endian>*, + unsigned int shndx); + + // Map file to write to. + FILE* map_file_; + // Whether we have printed the archive member header. + bool printed_archive_header_; + // Whether we have printed the allocated common header. + bool printed_common_header_; + // Whether we have printed the memory map header. + bool printed_memory_map_header_; +}; + +} // End namespace gold. + +#endif // !defined(GOLD_MAP_H) diff --git a/gold/merge.h b/gold/merge.h index cbc8bec..2aeff1e 100644 --- a/gold/merge.h +++ b/gold/merge.h @@ -283,6 +283,11 @@ class Output_merge_data : public Output_merge_base void do_write_to_buffer(unsigned char*); + // Write to a map file. + void + do_print_to_mapfile(Mapfile* mapfile) const + { mapfile->print_output_data(this, _("** merge constants")); } + // Print merge stats to stderr. void do_print_merge_stats(const char* section_name); @@ -400,6 +405,11 @@ class Output_merge_string : public Output_merge_base void do_write_to_buffer(unsigned char*); + // Write to a map file. + void + do_print_to_mapfile(Mapfile* mapfile) const + { mapfile->print_output_data(this, _("** merge strings")); } + // Print merge stats to stderr. void do_print_merge_stats(const char* section_name); diff --git a/gold/object.h b/gold/object.h index 52359af..4a01843 100644 --- a/gold/object.h +++ b/gold/object.h @@ -1239,6 +1239,12 @@ class Sized_relobj : public Relobj void setup(const typename elfcpp::Ehdr<size, big_endian>&); + // Return the number of symbols. This is only valid after + // Object::add_symbols has been called. + unsigned int + symbol_count() const + { return this->local_symbol_count_ + this->symbols_.size(); } + // If SYM is the index of a global symbol in the object file's // symbol table, return the Symbol object. Otherwise, return NULL. Symbol* diff --git a/gold/options.cc b/gold/options.cc index 8d18c11..da30a6d 100644 --- a/gold/options.cc +++ b/gold/options.cc @@ -697,6 +697,13 @@ General_options::finalize() this->set_do_demangle(getenv("COLLECT_NO_DEMANGLE") == NULL); } + // -M is equivalent to "-Map -". + if (this->print_map() && !this->user_set_Map()) + { + this->set_Map("-"); + this->set_user_set_Map(); + } + // If --thread_count is specified, it applies to // --thread-count-{initial,middle,final}, though it doesn't override // them. diff --git a/gold/options.h b/gold/options.h index 9a474df..e34e165 100644 --- a/gold/options.h +++ b/gold/options.h @@ -654,6 +654,11 @@ class General_options DEFINE_string(m, options::EXACTLY_ONE_DASH, 'm', "", N_("Ignored for compatibility"), N_("EMULATION")); + DEFINE_bool(print_map, options::TWO_DASHES, 'M', false, + N_("Write map file on standard output"), NULL); + DEFINE_string(Map, options::ONE_DASH, '\0', NULL, N_("Write map file"), + N_("MAPFILENAME")); + DEFINE_enable(new_dtags, options::EXACTLY_TWO_DASHES, '\0', false, N_("Enable use of DT_RUNPATH and DT_FLAGS"), N_("Disable use of DT_RUNPATH and DT_FLAGS")); diff --git a/gold/output.cc b/gold/output.cc index b5791f4..a3dab39 100644 --- a/gold/output.cc +++ b/gold/output.cc @@ -1701,6 +1701,25 @@ Output_section::Input_section::write_to_buffer(unsigned char* buffer) this->u2_.posd->write_to_buffer(buffer); } +// Print to a map file. + +void +Output_section::Input_section::print_to_mapfile(Mapfile* mapfile) const +{ + switch (this->shndx_) + { + case OUTPUT_SECTION_CODE: + case MERGE_DATA_SECTION_CODE: + case MERGE_STRING_SECTION_CODE: + this->u2_.posd->print_to_mapfile(mapfile); + break; + + default: + mapfile->print_input_section(this->u2_.object, this->shndx_); + break; + } +} + // Output_section methods. // Construct an Output_section. NAME will point into a Stringpool. @@ -1859,7 +1878,8 @@ Output_section::add_input_section(Sized_relobj<size, big_endian>* object, if (have_sections_script || !this->input_sections_.empty() || this->may_sort_attached_input_sections() - || this->must_sort_attached_input_sections()) + || this->must_sort_attached_input_sections() + || parameters->options().user_set_Map()) this->input_sections_.push_back(Input_section(object, shndx, shdr.get_sh_size(), addralign)); @@ -2546,6 +2566,19 @@ Output_section::add_input_section_for_script(Relobj* object, data_size, addralign)); } +// Print to the map file. + +void +Output_section::do_print_to_mapfile(Mapfile* mapfile) const +{ + mapfile->print_output_section(this); + + for (Input_section_list::const_iterator p = this->input_sections_.begin(); + p != this->input_sections_.end(); + ++p) + p->print_to_mapfile(mapfile); +} + // Print stats for merge sections to stderr. void @@ -3236,6 +3269,29 @@ Output_segment::write_section_headers_list(const Layout* layout, return v; } +// Print the output sections to the map file. + +void +Output_segment::print_sections_to_mapfile(Mapfile* mapfile) const +{ + if (this->type() != elfcpp::PT_LOAD) + return; + this->print_section_list_to_mapfile(mapfile, &this->output_data_); + this->print_section_list_to_mapfile(mapfile, &this->output_bss_); +} + +// Print an output section list to the map file. + +void +Output_segment::print_section_list_to_mapfile(Mapfile* mapfile, + const Output_data_list* pdl) const +{ + for (Output_data_list::const_iterator p = pdl->begin(); + p != pdl->end(); + ++p) + (*p)->print_to_mapfile(mapfile); +} + // Output_file methods. Output_file::Output_file(const char* name) diff --git a/gold/output.h b/gold/output.h index a8f2f39..dceaceb 100644 --- a/gold/output.h +++ b/gold/output.h @@ -27,6 +27,7 @@ #include <vector> #include "elfcpp.h" +#include "mapfile.h" #include "layout.h" #include "reloc-types.h" @@ -240,6 +241,11 @@ class Output_data is_data_size_valid() const { return this->is_data_size_valid_; } + // Print information to the map file. + void + print_to_mapfile(Mapfile* mapfile) const + { return this->do_print_to_mapfile(mapfile); } + protected: // Functions that child classes may or in some cases must implement. @@ -316,6 +322,12 @@ class Output_data do_tls_offset() const { gold_unreachable(); } + // Print to the map file. This only needs to be implemented by + // classes which may appear in a PT_LOAD segment. + virtual void + do_print_to_mapfile(Mapfile*) const + { gold_unreachable(); } + // Functions that child classes may call. // Set the size of the data. @@ -397,6 +409,11 @@ class Output_section_headers : public Output_data do_addralign() const { return Output_data::default_alignment(); } + // Write to a map file. + void + do_print_to_mapfile(Mapfile* mapfile) const + { mapfile->print_output_data(this, _("** section headers")); } + private: // Write the data to the file with the right size and endianness. template<int size, bool big_endian> @@ -428,6 +445,11 @@ class Output_segment_headers : public Output_data do_addralign() const { return Output_data::default_alignment(); } + // Write to a map file. + void + do_print_to_mapfile(Mapfile* mapfile) const + { mapfile->print_output_data(this, _("** segment headers")); } + private: // Write the data to the file with the right size and endianness. template<int size, bool big_endian> @@ -462,6 +484,11 @@ class Output_file_header : public Output_data do_addralign() const { return Output_data::default_alignment(); } + // Write to a map file. + void + do_print_to_mapfile(Mapfile* mapfile) const + { mapfile->print_output_data(this, _("** file header")); } + private: // Write the data to the file with the right size and endianness. template<int size, bool big_endian> @@ -663,6 +690,11 @@ class Output_data_const : public Output_section_data do_write_to_buffer(unsigned char* buffer) { memcpy(buffer, this->data_.data(), this->data_.size()); } + // Write to a map file. + void + do_print_to_mapfile(Mapfile* mapfile) const + { mapfile->print_output_data(this, _("** fill")); } + private: std::string data_; }; @@ -674,8 +706,9 @@ class Output_data_const_buffer : public Output_section_data { public: Output_data_const_buffer(const unsigned char* p, off_t len, - uint64_t addralign) - : Output_section_data(len, addralign), p_(p) + uint64_t addralign, const char* map_name) + : Output_section_data(len, addralign), + p_(p), map_name_(map_name) { } protected: @@ -688,8 +721,17 @@ class Output_data_const_buffer : public Output_section_data do_write_to_buffer(unsigned char* buffer) { memcpy(buffer, this->p_, this->data_size()); } + // Write to a map file. + void + do_print_to_mapfile(Mapfile* mapfile) const + { mapfile->print_output_data(this, _(this->map_name_)); } + private: + // The data to output. const unsigned char* p_; + // Name to use in a map file. Maps are a rarely used feature, but + // the space usage is minor as aren't very many of these objects. + const char* map_name_; }; // A place holder for a fixed amount of data written out via some @@ -698,8 +740,10 @@ class Output_data_const_buffer : public Output_section_data class Output_data_fixed_space : public Output_section_data { public: - Output_data_fixed_space(off_t data_size, uint64_t addralign) - : Output_section_data(data_size, addralign) + Output_data_fixed_space(off_t data_size, uint64_t addralign, + const char* map_name) + : Output_section_data(data_size, addralign), + map_name_(map_name) { } protected: @@ -708,6 +752,16 @@ class Output_data_fixed_space : public Output_section_data void do_write(Output_file*) { } + + // Write to a map file. + void + do_print_to_mapfile(Mapfile* mapfile) const + { mapfile->print_output_data(this, _(this->map_name_)); } + + private: + // Name to use in a map file. Maps are a rarely used feature, but + // the space usage is minor as aren't very many of these objects. + const char* map_name_; }; // A place holder for variable sized data written out via some other @@ -716,8 +770,9 @@ class Output_data_fixed_space : public Output_section_data class Output_data_space : public Output_section_data_build { public: - explicit Output_data_space(uint64_t addralign) - : Output_section_data_build(addralign) + explicit Output_data_space(uint64_t addralign, const char* map_name) + : Output_section_data_build(addralign), + map_name_(map_name) { } // Set the alignment. @@ -731,6 +786,38 @@ class Output_data_space : public Output_section_data_build void do_write(Output_file*) { } + + // Write to a map file. + void + do_print_to_mapfile(Mapfile* mapfile) const + { mapfile->print_output_data(this, _(this->map_name_)); } + + private: + // Name to use in a map file. Maps are a rarely used feature, but + // the space usage is minor as aren't very many of these objects. + const char* map_name_; +}; + +// Fill fixed space with zeroes. This is just like +// Output_data_fixed_space, except that the map name is known. + +class Output_data_zero_fill : public Output_section_data +{ + public: + Output_data_zero_fill(off_t data_size, uint64_t addralign) + : Output_section_data(data_size, addralign) + { } + + protected: + // There is no data to write out. + void + do_write(Output_file*) + { } + + // Write to a map file. + void + do_print_to_mapfile(Mapfile* mapfile) const + { mapfile->print_output_data(this, "** zero fill"); } }; // A string table which goes into an output section. @@ -757,6 +844,11 @@ class Output_data_strtab : public Output_section_data do_write_to_buffer(unsigned char* buffer) { this->strtab_->write_to_buffer(buffer, this->data_size()); } + // Write to a map file. + void + do_print_to_mapfile(Mapfile* mapfile) const + { mapfile->print_output_data(this, _("** string table")); } + private: Stringpool* strtab_; }; @@ -1056,6 +1148,16 @@ class Output_data_reloc_base : public Output_section_data_build void do_adjust_output_section(Output_section *os); + // Write to a map file. + void + do_print_to_mapfile(Mapfile* mapfile) const + { + mapfile->print_output_data(this, + (dynamic + ? _("** dynamic relocs") + : _("** relocs"))); + } + // Add a relocation entry. void add(Output_data *od, const Output_reloc_type& reloc) @@ -1380,6 +1482,11 @@ class Output_relocatable_relocs : public Output_section_data do_write(Output_file*) { } + // Write to a map file. + void + do_print_to_mapfile(Mapfile* mapfile) const + { mapfile->print_output_data(this, _("** relocs")); } + private: // The relocs associated with this input section. Relocatable_relocs* rr_; @@ -1400,6 +1507,11 @@ class Output_data_group : public Output_section_data void do_write(Output_file*); + // Write to a map file. + void + do_print_to_mapfile(Mapfile* mapfile) const + { mapfile->print_output_data(this, _("** group")); } + private: // The input object. Sized_relobj<size, big_endian>* relobj_; @@ -1502,6 +1614,11 @@ class Output_data_got : public Output_section_data_build void do_write(Output_file*); + // Write to a map file. + void + do_print_to_mapfile(Mapfile* mapfile) const + { mapfile->print_output_data(this, _("** GOT")); } + private: // This POD class holds a single GOT entry. class Got_entry @@ -1639,6 +1756,11 @@ class Output_data_dynamic : public Output_section_data void do_write(Output_file*); + // Write to a map file. + void + do_print_to_mapfile(Mapfile* mapfile) const + { mapfile->print_output_data(this, _("** dynamic")); } + private: // This POD class holds a single dynamic entry. class Dynamic_entry @@ -1752,6 +1874,11 @@ class Output_symtab_xindex : public Output_section_data void do_write(Output_file*); + // Write to a map file. + void + do_print_to_mapfile(Mapfile* mapfile) const + { mapfile->print_output_data(this, _("** symtab xindex")); } + private: template<bool big_endian> void @@ -2262,6 +2389,10 @@ class Output_section : public Output_data do_finalize_name(Layout*) { } + // Print to the map file. + virtual void + do_print_to_mapfile(Mapfile*) const; + // Record that this section requires postprocessing after all // relocations have been applied. This is called by a child class. void @@ -2439,6 +2570,10 @@ class Output_section : public Output_data void write_to_buffer(unsigned char*); + // Print to a map file. + void + print_to_mapfile(Mapfile*) const; + // Print statistics about merge sections to stderr. void print_merge_stats(const char* section_name) @@ -2802,6 +2937,10 @@ class Output_segment write_section_headers(const Layout*, const Stringpool*, unsigned char* v, unsigned int* pshndx) const; + // Print the output sections in the map file. + void + print_sections_to_mapfile(Mapfile*) const; + private: Output_segment(const Output_segment&); Output_segment& operator=(const Output_segment&); @@ -2844,6 +2983,10 @@ class Output_segment const Output_data_list*, unsigned char* v, unsigned int* pshdx) const; + // Print a section list to the mapfile. + void + print_section_list_to_mapfile(Mapfile*, const Output_data_list*) const; + // The list of output data with contents attached to this segment. Output_data_list output_data_; // The list of output data without contents attached to this segment. diff --git a/gold/readsyms.cc b/gold/readsyms.cc index 18b91b4..bfb850a8 100644 --- a/gold/readsyms.cc +++ b/gold/readsyms.cc @@ -220,6 +220,7 @@ Read_symbols::do_read_symbols(Workqueue* workqueue) workqueue->queue_next(new Add_archive_symbols(this->symtab_, this->layout_, this->input_objects_, + this->mapfile_, arch, this->input_group_, this->this_blocker_, @@ -239,6 +240,7 @@ Read_symbols::do_read_symbols(Workqueue* workqueue) this->layout_, this->dirpath_, this->input_objects_, + this->mapfile_, this->input_group_, this->input_argument_, input_file, @@ -274,7 +276,8 @@ Read_symbols::do_group(Workqueue* workqueue) workqueue->queue_soon(new Read_symbols(this->options_, this->input_objects_, this->symtab_, this->layout_, - this->dirpath_, arg, input_group, + this->dirpath_, this->mapfile_, + arg, input_group, this_blocker, next_blocker)); this_blocker = next_blocker; } @@ -283,6 +286,7 @@ Read_symbols::do_group(Workqueue* workqueue) workqueue->queue_soon(new Finish_group(this->input_objects_, this->symtab_, this->layout_, + this->mapfile_, input_group, saw_undefined, this_blocker, @@ -411,7 +415,7 @@ Finish_group::run(Workqueue*) Task_lock_obj<Archive> tl(this, *p); (*p)->add_symbols(this->symtab_, this->layout_, - this->input_objects_); + this->input_objects_, this->mapfile_); } } @@ -459,9 +463,9 @@ Read_script::run(Workqueue* workqueue) bool used_next_blocker; if (!read_input_script(workqueue, this->options_, this->symtab_, this->layout_, this->dirpath_, this->input_objects_, - this->input_group_, this->input_argument_, - this->input_file_, this->next_blocker_, - &used_next_blocker)) + this->mapfile_, this->input_group_, + this->input_argument_, this->input_file_, + this->next_blocker_, &used_next_blocker)) { // Here we have to handle any other input file types we need. gold_error(_("%s: not an object or archive"), diff --git a/gold/readsyms.h b/gold/readsyms.h index 0ad89f8..f93d6db 100644 --- a/gold/readsyms.h +++ b/gold/readsyms.h @@ -56,12 +56,13 @@ class Read_symbols : public Task // symbols. Read_symbols(const General_options& options, Input_objects* input_objects, Symbol_table* symtab, Layout* layout, Dirsearch* dirpath, - const Input_argument* input_argument, Input_group* input_group, - Task_token* this_blocker, Task_token* next_blocker) + Mapfile* mapfile, const Input_argument* input_argument, + Input_group* input_group, Task_token* this_blocker, + Task_token* next_blocker) : options_(options), input_objects_(input_objects), symtab_(symtab), - layout_(layout), dirpath_(dirpath), input_argument_(input_argument), - input_group_(input_group), this_blocker_(this_blocker), - next_blocker_(next_blocker) + layout_(layout), dirpath_(dirpath), mapfile_(mapfile), + input_argument_(input_argument), input_group_(input_group), + this_blocker_(this_blocker), next_blocker_(next_blocker) { } ~Read_symbols(); @@ -94,6 +95,7 @@ class Read_symbols : public Task Symbol_table* symtab_; Layout* layout_; Dirsearch* dirpath_; + Mapfile* mapfile_; const Input_argument* input_argument_; Input_group* input_group_; Task_token* this_blocker_; @@ -184,11 +186,11 @@ class Finish_group : public Task { public: Finish_group(Input_objects* input_objects, Symbol_table* symtab, - Layout* layout, Input_group* input_group, + Layout* layout, Mapfile* mapfile, Input_group* input_group, int saw_undefined, Task_token* this_blocker, Task_token* next_blocker) : input_objects_(input_objects), symtab_(symtab), - layout_(layout), input_group_(input_group), + layout_(layout), mapfile_(mapfile), input_group_(input_group), saw_undefined_(saw_undefined), this_blocker_(this_blocker), next_blocker_(next_blocker) { } @@ -214,6 +216,7 @@ class Finish_group : public Task Input_objects* input_objects_; Symbol_table* symtab_; Layout* layout_; + Mapfile* mapfile_; Input_group* input_group_; int saw_undefined_; Task_token* this_blocker_; @@ -229,13 +232,15 @@ class Read_script : public Task public: Read_script(const General_options& options, Symbol_table* symtab, Layout* layout, Dirsearch* dirpath, Input_objects* input_objects, - Input_group* input_group, const Input_argument* input_argument, + Mapfile* mapfile, Input_group* input_group, + const Input_argument* input_argument, Input_file* input_file, Task_token* this_blocker, Task_token* next_blocker) : options_(options), symtab_(symtab), layout_(layout), dirpath_(dirpath), - input_objects_(input_objects), input_group_(input_group), - input_argument_(input_argument), input_file_(input_file), - this_blocker_(this_blocker), next_blocker_(next_blocker) + input_objects_(input_objects), mapfile_(mapfile), + input_group_(input_group), input_argument_(input_argument), + input_file_(input_file), this_blocker_(this_blocker), + next_blocker_(next_blocker) { } ~Read_script(); @@ -260,6 +265,7 @@ class Read_script : public Task Layout* layout_; Dirsearch* dirpath_; Input_objects* input_objects_; + Mapfile* mapfile_; Input_group* input_group_; const Input_argument* input_argument_; Input_file* input_file_; diff --git a/gold/script-sections.cc b/gold/script-sections.cc index 55db831..7f3a4da 100644 --- a/gold/script-sections.cc +++ b/gold/script-sections.cc @@ -426,7 +426,7 @@ Output_section_element_dot_assignment::set_section_addresses( - *dot_value); Output_section_data* posd; if (fill->empty()) - posd = new Output_data_fixed_space(length, 0); + posd = new Output_data_zero_fill(length, 0); else { std::string this_fill = this->get_fill_string(fill, length); @@ -482,6 +482,11 @@ class Output_data_expression : public Output_section_data void do_write_to_buffer(unsigned char*); + // Write to a map file. + void + do_print_to_mapfile(Mapfile* mapfile) const + { mapfile->print_output_data(this, _("** expression")); } + private: template<bool big_endian> void diff --git a/gold/script.cc b/gold/script.cc index a808b2e..4b2c337 100644 --- a/gold/script.cc +++ b/gold/script.cc @@ -1313,7 +1313,7 @@ bool read_input_script(Workqueue* workqueue, const General_options& options, Symbol_table* symtab, Layout* layout, Dirsearch* dirsearch, Input_objects* input_objects, - Input_group* input_group, + Mapfile* mapfile, Input_group* input_group, const Input_argument* input_argument, Input_file* input_file, Task_token* next_blocker, bool* used_next_blocker) @@ -1353,7 +1353,7 @@ read_input_script(Workqueue* workqueue, const General_options& options, nb->add_blocker(); } workqueue->queue_soon(new Read_symbols(options, input_objects, symtab, - layout, dirsearch, &*p, + layout, dirsearch, mapfile, &*p, input_group, this_blocker, nb)); this_blocker = nb; } diff --git a/gold/script.h b/gold/script.h index af0f53c..ea4b6af 100644 --- a/gold/script.h +++ b/gold/script.h @@ -43,6 +43,7 @@ class General_options; class Command_line; class Symbol_table; class Layout; +class Mapfile; class Input_argument; class Input_objects; class Input_group; @@ -393,7 +394,7 @@ class Script_options bool read_input_script(Workqueue*, const General_options&, Symbol_table*, Layout*, - Dirsearch*, Input_objects*, Input_group*, + Dirsearch*, Input_objects*, Mapfile*, Input_group*, const Input_argument*, Input_file*, Task_token* next_blocker, bool* used_next_blocker); diff --git a/gold/sparc.cc b/gold/sparc.cc index 13a069e..aa8bbbd 100644 --- a/gold/sparc.cc +++ b/gold/sparc.cc @@ -1059,6 +1059,11 @@ class Output_data_plt_sparc : public Output_section_data protected: void do_adjust_output_section(Output_section* os); + // Write to a map file. + void + do_print_to_mapfile(Mapfile* mapfile) const + { mapfile->print_output_data(this, _("** PLT")); } + private: // The size of an entry in the PLT. static const int base_plt_entry_size = (size == 32 ? 12 : 32); diff --git a/gold/symtab.h b/gold/symtab.h index d4ca787..7d99cd5 100644 --- a/gold/symtab.h +++ b/gold/symtab.h @@ -38,6 +38,7 @@ namespace gold { +class Mapfile; class Object; class Relobj; template<int size, bool big_endian> @@ -1177,7 +1178,7 @@ class Symbol_table // Allocate the common symbols void - allocate_commons(Layout*); + allocate_commons(Layout*, Mapfile*); // Add a warning for symbol NAME in object OBJ. WARNING is the text // of the warning. @@ -1374,12 +1375,12 @@ class Symbol_table // Allocate the common symbols, sized version. template<int size> void - do_allocate_commons(Layout*); + do_allocate_commons(Layout*, Mapfile*); // Allocate the common symbols from one list. template<int size> void - do_allocate_commons_list(Layout*, bool is_tls, Commons_type*); + do_allocate_commons_list(Layout*, bool is_tls, Commons_type*, Mapfile*); // Implement detect_odr_violations. template<int size, bool big_endian> diff --git a/gold/x86_64.cc b/gold/x86_64.cc index f523ae9..356505c 100644 --- a/gold/x86_64.cc +++ b/gold/x86_64.cc @@ -446,7 +446,7 @@ Target_x86_64::got_section(Symbol_table* symtab, Layout* layout) // create another set of data in the .got section. Note that we // always create a PLT if we create a GOT, although the PLT // might be empty. - this->got_plt_ = new Output_data_space(8); + this->got_plt_ = new Output_data_space(8, "** GOT PLT"); os = layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS, (elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE), @@ -526,6 +526,11 @@ class Output_data_plt_x86_64 : public Output_section_data void do_adjust_output_section(Output_section* os); + // Write to a map file. + void + do_print_to_mapfile(Mapfile* mapfile) const + { mapfile->print_output_data(this, _("** PLT")); } + private: // The size of an entry in the PLT. static const int plt_entry_size = 16; |