aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gold/gold.h4
-rw-r--r--gold/layout.cc75
-rw-r--r--gold/layout.h4
-rw-r--r--gold/version.cc8
4 files changed, 91 insertions, 0 deletions
diff --git a/gold/gold.h b/gold/gold.h
index 91669ee..63bcb79 100644
--- a/gold/gold.h
+++ b/gold/gold.h
@@ -211,6 +211,10 @@ extern void do_gold_unreachable(const char*, int, const char*)
extern void
print_version(bool print_short);
+// Get the version string.
+extern const char*
+get_version_string();
+
// Queue up the first set of tasks.
extern void
queue_initial_tasks(const General_options&,
diff --git a/gold/layout.cc b/gold/layout.cc
index e878456..af91d41 100644
--- a/gold/layout.cc
+++ b/gold/layout.cc
@@ -521,6 +521,8 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
target->finalize_sections(this);
+ this->create_note_section();
+
Output_segment* phdr_seg = NULL;
if (input_objects->any_dynamic())
{
@@ -606,6 +608,79 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
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_note_section()
+{
+ if (parameters->output_is_object())
+ return;
+
+ const int size = parameters->get_size();
+
+ // 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", 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);
+}
+
// 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.
diff --git a/gold/layout.h b/gold/layout.h
index 3e09d62..90cc22b 100644
--- a/gold/layout.h
+++ b/gold/layout.h
@@ -213,6 +213,10 @@ class Layout
const elfcpp::Shdr<size, big_endian>&,
Output_section*, off_t*);
+ // Create a .note section for gold.
+ void
+ create_note_section();
+
// Find the first read-only PT_LOAD segment, creating one if
// necessary.
Output_segment*
diff --git a/gold/version.cc b/gold/version.cc
index d7ad19c..dda3d7e 100644
--- a/gold/version.cc
+++ b/gold/version.cc
@@ -55,4 +55,12 @@ This program has absolutely no warranty.\n"));
}
}
+// Return the version string.
+
+const char*
+get_version_string()
+{
+ return version_string;
+}
+
} // End namespace gold.