mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-23 18:14:13 +08:00
* options.h (class General_options): Define build_id option.
* layout.h (class Layout): Declare write_build_id, create_note, create_build_id. Add build_id_note_ member. * layout.cc: Include <cerrno>, <fcntl.h>, <unistd.h>, "libiberty.h", "md5.h", "sha1.h". (Layout::Layout): Initialize eh_frame_data_, eh_frame_hdr_section_, and build_id_note_. (Layout::finalize): Call create_build_id. (Layout::create_note): New function, broken out of Layout::create_gold_note. (Layout::create_gold_note): Call create_note. (Layout::create_build_id): New function. (Layout::write_build_id): New function. (Close_task_runner::run): Call write_build_id.
This commit is contained in:
parent
baf4901374
commit
8ed814a99c
@ -1,5 +1,20 @@
|
|||||||
2008-03-24 Ian Lance Taylor <iant@google.com>
|
2008-03-24 Ian Lance Taylor <iant@google.com>
|
||||||
|
|
||||||
|
* options.h (class General_options): Define build_id option.
|
||||||
|
* layout.h (class Layout): Declare write_build_id, create_note,
|
||||||
|
create_build_id. Add build_id_note_ member.
|
||||||
|
* layout.cc: Include <cerrno>, <fcntl.h>, <unistd.h>,
|
||||||
|
"libiberty.h", "md5.h", "sha1.h".
|
||||||
|
(Layout::Layout): Initialize eh_frame_data_,
|
||||||
|
eh_frame_hdr_section_, and build_id_note_.
|
||||||
|
(Layout::finalize): Call create_build_id.
|
||||||
|
(Layout::create_note): New function, broken out of
|
||||||
|
Layout::create_gold_note.
|
||||||
|
(Layout::create_gold_note): Call create_note.
|
||||||
|
(Layout::create_build_id): New function.
|
||||||
|
(Layout::write_build_id): New function.
|
||||||
|
(Close_task_runner::run): Call write_build_id.
|
||||||
|
|
||||||
* x86_64.cc: Correct license to GPLv3.
|
* x86_64.cc: Correct license to GPLv3.
|
||||||
|
|
||||||
2008-03-23 Ian Lance Taylor <iant@google.com>
|
2008-03-23 Ian Lance Taylor <iant@google.com>
|
||||||
|
216
gold/layout.cc
216
gold/layout.cc
@ -22,10 +22,16 @@
|
|||||||
|
|
||||||
#include "gold.h"
|
#include "gold.h"
|
||||||
|
|
||||||
|
#include <cerrno>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "libiberty.h"
|
||||||
|
#include "md5.h"
|
||||||
|
#include "sha1.h"
|
||||||
|
|
||||||
#include "parameters.h"
|
#include "parameters.h"
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
@ -76,7 +82,8 @@ Layout::Layout(const General_options& options, Script_options* script_options)
|
|||||||
unattached_section_list_(), special_output_list_(),
|
unattached_section_list_(), special_output_list_(),
|
||||||
section_headers_(NULL), tls_segment_(NULL), symtab_section_(NULL),
|
section_headers_(NULL), tls_segment_(NULL), symtab_section_(NULL),
|
||||||
dynsym_section_(NULL), dynamic_section_(NULL), dynamic_data_(NULL),
|
dynsym_section_(NULL), dynamic_section_(NULL), dynamic_data_(NULL),
|
||||||
eh_frame_section_(NULL), group_signatures_(), output_file_size_(-1),
|
eh_frame_section_(NULL), eh_frame_data_(NULL), eh_frame_hdr_section_(NULL),
|
||||||
|
build_id_note_(NULL), group_signatures_(), output_file_size_(-1),
|
||||||
input_requires_executable_stack_(false),
|
input_requires_executable_stack_(false),
|
||||||
input_with_gnu_stack_note_(false),
|
input_with_gnu_stack_note_(false),
|
||||||
input_without_gnu_stack_note_(false),
|
input_without_gnu_stack_note_(false),
|
||||||
@ -1035,6 +1042,7 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
|
|||||||
|
|
||||||
this->create_gold_note();
|
this->create_gold_note();
|
||||||
this->create_executable_stack_info(target);
|
this->create_executable_stack_info(target);
|
||||||
|
this->create_build_id();
|
||||||
|
|
||||||
Output_segment* phdr_seg = NULL;
|
Output_segment* phdr_seg = NULL;
|
||||||
if (!parameters->options().relocatable() && !parameters->doing_static_link())
|
if (!parameters->options().relocatable() && !parameters->doing_static_link())
|
||||||
@ -1181,15 +1189,16 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
|
|||||||
return off;
|
return off;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a .note section for an executable or shared library. This
|
// Create a note header following the format defined in the ELF ABI.
|
||||||
// records the version of gold used to create the binary.
|
// NAME is the name, NOTE_TYPE is the type, DESCSZ is the size of the
|
||||||
|
// descriptor. ALLOCATE is true if the section should be allocated in
|
||||||
|
// memory. This returns the new note section. It sets
|
||||||
|
// *TRAILING_PADDING to the number of trailing zero bytes required.
|
||||||
|
|
||||||
void
|
Output_section*
|
||||||
Layout::create_gold_note()
|
Layout::create_note(const char* name, int note_type, size_t descsz,
|
||||||
|
bool allocate, size_t* trailing_padding)
|
||||||
{
|
{
|
||||||
if (parameters->options().relocatable())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Authorities all agree that the values in a .note field should
|
// Authorities all agree that the values in a .note field should
|
||||||
// be aligned on 4-byte boundaries for 32-bit binaries. However,
|
// be aligned on 4-byte boundaries for 32-bit binaries. However,
|
||||||
// they differ on what the alignment is for 64-bit binaries.
|
// they differ on what the alignment is for 64-bit binaries.
|
||||||
@ -1208,19 +1217,14 @@ Layout::create_gold_note()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// The contents of the .note section.
|
// 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 namesz = strlen(name) + 1;
|
||||||
size_t aligned_namesz = align_address(namesz, size / 8);
|
size_t aligned_namesz = align_address(namesz, size / 8);
|
||||||
size_t descsz = desc.length() + 1;
|
|
||||||
size_t aligned_descsz = align_address(descsz, size / 8);
|
size_t aligned_descsz = align_address(descsz, size / 8);
|
||||||
const int note_type = 4;
|
|
||||||
|
|
||||||
size_t notesz = 3 * (size / 8) + aligned_namesz + aligned_descsz;
|
size_t notehdrsz = 3 * (size / 8) + aligned_namesz;
|
||||||
|
|
||||||
unsigned char buffer[128];
|
unsigned char* buffer = new unsigned char[notehdrsz];
|
||||||
gold_assert(sizeof buffer >= notesz);
|
memset(buffer, 0, notehdrsz);
|
||||||
memset(buffer, 0, notesz);
|
|
||||||
|
|
||||||
bool is_big_endian = parameters->target().is_big_endian();
|
bool is_big_endian = parameters->target().is_big_endian();
|
||||||
|
|
||||||
@ -1258,15 +1262,46 @@ Layout::create_gold_note()
|
|||||||
gold_unreachable();
|
gold_unreachable();
|
||||||
|
|
||||||
memcpy(buffer + 3 * (size / 8), name, namesz);
|
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);
|
const char* note_name = this->namepool_.add(".note", false, NULL);
|
||||||
|
elfcpp::Elf_Xword flags = 0;
|
||||||
|
if (allocate)
|
||||||
|
flags = elfcpp::SHF_ALLOC;
|
||||||
Output_section* os = this->make_output_section(note_name,
|
Output_section* os = this->make_output_section(note_name,
|
||||||
elfcpp::SHT_NOTE,
|
elfcpp::SHT_NOTE,
|
||||||
0);
|
flags);
|
||||||
Output_section_data* posd = new Output_data_const(buffer, notesz,
|
Output_section_data* posd = new Output_data_const_buffer(buffer, notehdrsz,
|
||||||
size / 8);
|
size / 8);
|
||||||
os->add_output_section_data(posd);
|
os->add_output_section_data(posd);
|
||||||
|
|
||||||
|
*trailing_padding = aligned_descsz - descsz;
|
||||||
|
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For an executable or shared library, create a note to record the
|
||||||
|
// version of gold used to create the binary.
|
||||||
|
|
||||||
|
void
|
||||||
|
Layout::create_gold_note()
|
||||||
|
{
|
||||||
|
if (parameters->options().relocatable())
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::string desc = std::string("gold ") + gold::get_version_string();
|
||||||
|
|
||||||
|
size_t trailing_padding;
|
||||||
|
Output_section *os = this->create_note("GNU", elfcpp::NT_GNU_GOLD_VERSION,
|
||||||
|
desc.size(), false, &trailing_padding);
|
||||||
|
|
||||||
|
Output_section_data* posd = new Output_data_const(desc, 4);
|
||||||
|
os->add_output_section_data(posd);
|
||||||
|
|
||||||
|
if (trailing_padding > 0)
|
||||||
|
{
|
||||||
|
posd = new Output_data_fixed_space(trailing_padding, 0);
|
||||||
|
os->add_output_section_data(posd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Record whether the stack should be executable. This can be set
|
// Record whether the stack should be executable. This can be set
|
||||||
@ -1318,6 +1353,104 @@ Layout::create_executable_stack_info(const Target* target)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If --build-id was used, set up the build ID note.
|
||||||
|
|
||||||
|
void
|
||||||
|
Layout::create_build_id()
|
||||||
|
{
|
||||||
|
if (!parameters->options().user_set_build_id())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const char* style = parameters->options().build_id();
|
||||||
|
if (strcmp(style, "none") == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Set DESCSZ to the size of the note descriptor. When possible,
|
||||||
|
// set DESC to the note descriptor contents.
|
||||||
|
size_t descsz;
|
||||||
|
std::string desc;
|
||||||
|
if (strcmp(style, "md5") == 0)
|
||||||
|
descsz = 128 / 8;
|
||||||
|
else if (strcmp(style, "sha1") == 0)
|
||||||
|
descsz = 160 / 8;
|
||||||
|
else if (strcmp(style, "uuid") == 0)
|
||||||
|
{
|
||||||
|
const size_t uuidsz = 128 / 8;
|
||||||
|
|
||||||
|
char buffer[uuidsz];
|
||||||
|
memset(buffer, 0, uuidsz);
|
||||||
|
|
||||||
|
int descriptor = ::open("/dev/urandom", O_RDONLY);
|
||||||
|
if (descriptor < 0)
|
||||||
|
gold_error(_("--build-id=uuid failed: could not open /dev/urandom: %s"),
|
||||||
|
strerror(errno));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ssize_t got = ::read(descriptor, buffer, uuidsz);
|
||||||
|
::close(descriptor);
|
||||||
|
if (got < 0)
|
||||||
|
gold_error(_("/dev/urandom: read failed: %s"), strerror(errno));
|
||||||
|
else if (static_cast<size_t>(got) != uuidsz)
|
||||||
|
gold_error(_("/dev/urandom: expected %zu bytes, got %zd bytes"),
|
||||||
|
uuidsz, got);
|
||||||
|
}
|
||||||
|
|
||||||
|
desc.assign(buffer, uuidsz);
|
||||||
|
descsz = uuidsz;
|
||||||
|
}
|
||||||
|
else if (strncmp(style, "0x", 2) == 0)
|
||||||
|
{
|
||||||
|
hex_init();
|
||||||
|
const char* p = style + 2;
|
||||||
|
while (*p != '\0')
|
||||||
|
{
|
||||||
|
if (hex_p(p[0]) && hex_p(p[1]))
|
||||||
|
{
|
||||||
|
char c = (hex_value(p[0]) << 4) | hex_value(p[1]);
|
||||||
|
desc += c;
|
||||||
|
p += 2;
|
||||||
|
}
|
||||||
|
else if (*p == '-' || *p == ':')
|
||||||
|
++p;
|
||||||
|
else
|
||||||
|
gold_fatal(_("--build-id argument '%s' not a valid hex number"),
|
||||||
|
style);
|
||||||
|
}
|
||||||
|
descsz = desc.size();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
gold_fatal(_("unrecognized --build-id argument '%s'"), style);
|
||||||
|
|
||||||
|
// Create the note.
|
||||||
|
size_t trailing_padding;
|
||||||
|
Output_section* os = this->create_note("GNU", elfcpp::NT_GNU_BUILD_ID,
|
||||||
|
descsz, true, &trailing_padding);
|
||||||
|
|
||||||
|
if (!desc.empty())
|
||||||
|
{
|
||||||
|
// We know the value already, so we fill it in now.
|
||||||
|
gold_assert(desc.size() == descsz);
|
||||||
|
|
||||||
|
Output_section_data* posd = new Output_data_const(desc, 4);
|
||||||
|
os->add_output_section_data(posd);
|
||||||
|
|
||||||
|
if (trailing_padding != 0)
|
||||||
|
{
|
||||||
|
posd = new Output_data_fixed_space(trailing_padding, 0);
|
||||||
|
os->add_output_section_data(posd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 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);
|
||||||
|
os->add_output_section_data(this->build_id_note_);
|
||||||
|
os->set_after_input_sections();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Return whether SEG1 should be before SEG2 in the output file. This
|
// Return whether SEG1 should be before SEG2 in the output file. This
|
||||||
// is based entirely on the segment type and flags. When this is
|
// is based entirely on the segment type and flags. When this is
|
||||||
// called the segment addresses has normally not yet been set.
|
// called the segment addresses has normally not yet been set.
|
||||||
@ -2676,6 +2809,46 @@ Layout::write_sections_after_input_sections(Output_file* of)
|
|||||||
this->section_headers_->write(of);
|
this->section_headers_->write(of);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the build ID requires computing a checksum, do so here, and
|
||||||
|
// write it out. We compute a checksum over the entire file because
|
||||||
|
// that is simplest.
|
||||||
|
|
||||||
|
void
|
||||||
|
Layout::write_build_id(Output_file* of) const
|
||||||
|
{
|
||||||
|
if (this->build_id_note_ == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const unsigned char* iv = of->get_input_view(0, this->output_file_size_);
|
||||||
|
|
||||||
|
unsigned char* ov = of->get_output_view(this->build_id_note_->offset(),
|
||||||
|
this->build_id_note_->data_size());
|
||||||
|
|
||||||
|
const char* style = parameters->options().build_id();
|
||||||
|
if (strcmp(style, "sha1") == 0)
|
||||||
|
{
|
||||||
|
sha1_ctx ctx;
|
||||||
|
sha1_init_ctx(&ctx);
|
||||||
|
sha1_process_bytes(iv, this->output_file_size_, &ctx);
|
||||||
|
sha1_finish_ctx(&ctx, ov);
|
||||||
|
}
|
||||||
|
else if (strcmp(style, "md5") == 0)
|
||||||
|
{
|
||||||
|
md5_ctx ctx;
|
||||||
|
md5_init_ctx(&ctx);
|
||||||
|
md5_process_bytes(iv, this->output_file_size_, &ctx);
|
||||||
|
md5_finish_ctx(&ctx, ov);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
gold_unreachable();
|
||||||
|
|
||||||
|
of->write_output_view(this->build_id_note_->offset(),
|
||||||
|
this->build_id_note_->data_size(),
|
||||||
|
ov);
|
||||||
|
|
||||||
|
of->free_input_view(0, this->output_file_size_, iv);
|
||||||
|
}
|
||||||
|
|
||||||
// Write out a binary file. This is called after the link is
|
// Write out a binary file. This is called after the link is
|
||||||
// complete. IN is the temporary output file we used to generate the
|
// complete. IN is the temporary output file we used to generate the
|
||||||
// ELF code. We simply walk through the segments, read them from
|
// ELF code. We simply walk through the segments, read them from
|
||||||
@ -2856,6 +3029,9 @@ Write_after_input_sections_task::run(Workqueue*)
|
|||||||
void
|
void
|
||||||
Close_task_runner::run(Workqueue*, const Task*)
|
Close_task_runner::run(Workqueue*, const Task*)
|
||||||
{
|
{
|
||||||
|
// If we need to compute a checksum for the BUILD if, we do so here.
|
||||||
|
this->layout_->write_build_id(this->of_);
|
||||||
|
|
||||||
// If we've been asked to create a binary file, we do so here.
|
// If we've been asked to create a binary file, we do so here.
|
||||||
if (this->options_->oformat_enum() != General_options::OBJECT_FORMAT_ELF)
|
if (this->options_->oformat_enum() != General_options::OBJECT_FORMAT_ELF)
|
||||||
this->layout_->write_binary(this->of_);
|
this->layout_->write_binary(this->of_);
|
||||||
|
@ -294,6 +294,10 @@ class Layout
|
|||||||
script_options() const
|
script_options() const
|
||||||
{ return this->script_options_; }
|
{ return this->script_options_; }
|
||||||
|
|
||||||
|
// Compute and write out the build ID if needed.
|
||||||
|
void
|
||||||
|
write_build_id(Output_file*) const;
|
||||||
|
|
||||||
// Rewrite output file in binary format.
|
// Rewrite output file in binary format.
|
||||||
void
|
void
|
||||||
write_binary(Output_file* in) const;
|
write_binary(Output_file* in) const;
|
||||||
@ -370,6 +374,11 @@ class Layout
|
|||||||
};
|
};
|
||||||
typedef std::vector<Group_signature> Group_signatures;
|
typedef std::vector<Group_signature> Group_signatures;
|
||||||
|
|
||||||
|
// Create a .note section, filling in the header.
|
||||||
|
Output_section*
|
||||||
|
create_note(const char* name, int note_type, size_t descsz,
|
||||||
|
bool allocate, size_t* trailing_padding);
|
||||||
|
|
||||||
// Create a .note section for gold.
|
// Create a .note section for gold.
|
||||||
void
|
void
|
||||||
create_gold_note();
|
create_gold_note();
|
||||||
@ -378,6 +387,10 @@ class Layout
|
|||||||
void
|
void
|
||||||
create_executable_stack_info(const Target*);
|
create_executable_stack_info(const Target*);
|
||||||
|
|
||||||
|
// Create a build ID note if needed.
|
||||||
|
void
|
||||||
|
create_build_id();
|
||||||
|
|
||||||
// Find the first read-only PT_LOAD segment, creating one if
|
// Find the first read-only PT_LOAD segment, creating one if
|
||||||
// necessary.
|
// necessary.
|
||||||
Output_segment*
|
Output_segment*
|
||||||
@ -586,6 +599,8 @@ class Layout
|
|||||||
Eh_frame* eh_frame_data_;
|
Eh_frame* eh_frame_data_;
|
||||||
// The exception frame header output section if there is one.
|
// The exception frame header output section if there is one.
|
||||||
Output_section* eh_frame_hdr_section_;
|
Output_section* eh_frame_hdr_section_;
|
||||||
|
// The space for the build ID checksum if there is one.
|
||||||
|
Output_section_data* build_id_note_;
|
||||||
// A list of group sections and their signatures.
|
// A list of group sections and their signatures.
|
||||||
Group_signatures group_signatures_;
|
Group_signatures group_signatures_;
|
||||||
// The size of the output file.
|
// The size of the output file.
|
||||||
|
@ -460,6 +460,10 @@ class General_options
|
|||||||
DEFINE_bool(Bsymbolic, options::ONE_DASH, '\0', false,
|
DEFINE_bool(Bsymbolic, options::ONE_DASH, '\0', false,
|
||||||
N_("Bind defined symbols locally"), NULL);
|
N_("Bind defined symbols locally"), NULL);
|
||||||
|
|
||||||
|
DEFINE_optional_string(build_id, options::TWO_DASHES, '\0', "sha1",
|
||||||
|
N_("Generate build ID note"),
|
||||||
|
N_("[=STYLE]"));
|
||||||
|
|
||||||
#ifdef HAVE_ZLIB_H
|
#ifdef HAVE_ZLIB_H
|
||||||
DEFINE_enum(compress_debug_sections, options::TWO_DASHES, '\0', "none",
|
DEFINE_enum(compress_debug_sections, options::TWO_DASHES, '\0', "none",
|
||||||
N_("Compress .debug_* sections in the output file"),
|
N_("Compress .debug_* sections in the output file"),
|
||||||
|
Loading…
Reference in New Issue
Block a user