summaryrefslogtreecommitdiff
path: root/gold/incremental.cc
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@airs.com>2009-10-09 16:40:51 +0000
committerIan Lance Taylor <ian@airs.com>2009-10-09 16:40:51 +0000
commitc549a6949c8cbbbeafa79ab903b172bbc5f2b8ea (patch)
treed7881e3b7056774b661607d3d3ae9e56e3a14ebf /gold/incremental.cc
parente322137b9b864508a8b8f378ebb331589812ed18 (diff)
downloadbinutils-gdb-c549a6949c8cbbbeafa79ab903b172bbc5f2b8ea.tar.gz
elfcpp/:
* elfcpp_file.h: Fix header guard. Include <cstdio>. (class Elf_recognizer): New class, code from gold/object.cc. (Elf_file::find_section_by_type): New method. gold/: * incremental.cc: Include <cstdarg> and "target-select.h". (vexplain_no_incremental): New function. (explain_no_incremental): New function. (Incremental_binary::error): New method. (Sized_incremental_binary::do_find_incremental_inputs_section): New method. (make_sized_incremental_binary): New function. (open_incremental_binary): New function. (can_incrementally_link_file): Add checks if output is ELF and has inputs section. * incremental.h: Include "elfcpp_file.h" and "output.h". (Incremental_binary): New class. (Sized_incremental_binary): New class. (open_incremental_binary): Declare. * object.cc (is_elf_object): Use elfcpp::Elf_recognizer::is_elf_file. (make_elf_object): Use elfcpp::Elf_recognizer::is_valid_header. * output.h (Output_file::filesize): New method.
Diffstat (limited to 'gold/incremental.cc')
-rw-r--r--gold/incremental.cc192
1 files changed, 192 insertions, 0 deletions
diff --git a/gold/incremental.cc b/gold/incremental.cc
index 4a3ecb1a691..9f7c4c20ec1 100644
--- a/gold/incremental.cc
+++ b/gold/incremental.cc
@@ -21,11 +21,15 @@
// MA 02110-1301, USA.
#include "gold.h"
+
+#include <cstdarg>
+
#include "elfcpp.h"
#include "output.h"
#include "incremental.h"
#include "archive.h"
#include "output.h"
+#include "target-select.h"
using elfcpp::Convert;
@@ -150,6 +154,162 @@ class Incremental_inputs_entry_write
internal::Incremental_inputs_entry_data* p_;
};
+// Inform the user why we don't do an incremental link. Not called in
+// the obvious case of missing output file. TODO: Is this helpful?
+
+void
+vexplain_no_incremental(const char* format, va_list args)
+{
+ char* buf = NULL;
+ if (vasprintf(&buf, format, args) < 0)
+ gold_nomem();
+ gold_info(_("the link might take longer: "
+ "cannot perform incremental link: %s"), buf);
+ free(buf);
+}
+
+void
+explain_no_incremental(const char* format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ vexplain_no_incremental(format, args);
+ va_end(args);
+}
+
+// Report an error.
+
+void
+Incremental_binary::error(const char* format, ...) const
+{
+ va_list args;
+ va_start(args, format);
+ // Current code only checks if the file can be used for incremental linking,
+ // so errors shouldn't fail the build, but only result in a fallback to a
+ // full build.
+ // TODO: when we implement incremental editing of the file, we may need a
+ // flag that will cause errors to be treated seriously.
+ vexplain_no_incremental(format, args);
+ va_end(args);
+}
+
+template<int size, bool big_endian>
+bool
+Sized_incremental_binary<size, big_endian>::do_find_incremental_inputs_section(
+ Location* location)
+{
+ unsigned int shndx = this->elf_file_.find_section_by_type(
+ elfcpp::SHT_GNU_INCREMENTAL_INPUTS);
+ if (shndx == elfcpp::SHN_UNDEF) // Not found.
+ return false;
+ *location = this->elf_file_.section_contents(shndx);
+ return true;
+}
+
+namespace
+{
+
+// Create a Sized_incremental_binary object of the specified size and
+// endianness. Fails if the target architecture is not supported.
+
+template<int size, bool big_endian>
+Incremental_binary*
+make_sized_incremental_binary(Output_file* file,
+ const elfcpp::Ehdr<size, big_endian>& ehdr)
+{
+ Target* target = select_target(ehdr.get_e_machine(), size, big_endian,
+ ehdr.get_e_ident()[elfcpp::EI_OSABI],
+ ehdr.get_e_ident()[elfcpp::EI_ABIVERSION]);
+ if (target == NULL)
+ {
+ explain_no_incremental(_("unsupported ELF machine number %d"),
+ ehdr.get_e_machine());
+ return NULL;
+ }
+
+ return new Sized_incremental_binary<size, big_endian>(file, ehdr, target);
+}
+
+} // End of anonymous namespace.
+
+// Create an Incremental_binary object for FILE. Returns NULL is this is not
+// possible, e.g. FILE is not an ELF file or has an unsupported target. FILE
+// should be opened.
+
+Incremental_binary*
+open_incremental_binary(Output_file* file)
+{
+ off_t filesize = file->filesize();
+ int want = elfcpp::Elf_recognizer::max_header_size;
+ if (filesize < want)
+ want = filesize;
+
+ const unsigned char* p = file->get_input_view(0, want);
+ if (!elfcpp::Elf_recognizer::is_elf_file(p, want))
+ {
+ explain_no_incremental(_("output is not an ELF file."));
+ return NULL;
+ }
+
+ int size;
+ bool big_endian;
+ std::string error;
+ if (!elfcpp::Elf_recognizer::is_valid_header(p, want, &size, &big_endian,
+ &error))
+ {
+ explain_no_incremental(error.c_str());
+ return NULL;
+ }
+
+ Incremental_binary* result = NULL;
+ if (size == 32)
+ {
+ if (big_endian)
+ {
+#ifdef HAVE_TARGET_32_BIG
+ result = make_sized_incremental_binary<32, true>(
+ file, elfcpp::Ehdr<32, true>(p));
+#else
+ explain_no_incremental(_("unsupported file: 32-bit, big-endian"));
+#endif
+ }
+ else
+ {
+#ifdef HAVE_TARGET_32_LITTLE
+ result = make_sized_incremental_binary<32, false>(
+ file, elfcpp::Ehdr<32, false>(p));
+#else
+ explain_no_incremental(_("unsupported file: 32-bit, little-endian"));
+#endif
+ }
+ }
+ else if (size == 64)
+ {
+ if (big_endian)
+ {
+#ifdef HAVE_TARGET_64_BIG
+ result = make_sized_incremental_binary<64, true>(
+ file, elfcpp::Ehdr<64, true>(p));
+#else
+ explain_no_incremental(_("unsupported file: 64-bit, big-endian"));
+#endif
+ }
+ else
+ {
+#ifdef HAVE_TARGET_64_LITTLE
+ result = make_sized_incremental_binary<64, false>(
+ file, elfcpp::Ehdr<64, false>(p));
+#else
+ explain_no_incremental(_("unsupported file: 64-bit, little-endian"));
+#endif
+ }
+ }
+ else
+ gold_unreachable();
+
+ return result;
+}
+
// Analyzes the output file to check if incremental linking is possible and
// (to be done) what files need to be relinked.
@@ -159,6 +319,16 @@ Incremental_checker::can_incrementally_link_output_file()
Output_file output(this->output_name_);
if (!output.open_for_modification())
return false;
+ Incremental_binary* binary = open_incremental_binary(&output);
+ if (binary == NULL)
+ return false;
+ Incremental_binary::Location inputs_location;
+ if (!binary->find_incremental_inputs_section(&inputs_location))
+ {
+ explain_no_incremental("no incremental data from previous build");
+ delete binary;
+ return false;
+ }
return true;
}
@@ -392,4 +562,26 @@ Incremental_inputs::sized_create_inputs_section_data()
"** incremental link inputs list");
}
+// Instantiate the templates we need.
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+class Sized_incremental_binary<32, false>;
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+class Sized_incremental_binary<32, true>;
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+class Sized_incremental_binary<64, false>;
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+class Sized_incremental_binary<64, true>;
+#endif
+
} // End namespace gold.