From bc644c6cfca852cd34e486a018bfde7fd1ac55e8 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 8 Feb 2008 07:06:58 +0000 Subject: [PATCH] Add support for --format binary for input files. --- gold/Makefile.am | 2 + gold/Makefile.in | 5 +- gold/binary.cc | 356 ++++++++++++++++++++++++++++++ gold/binary.h | 116 ++++++++++ gold/fileread.cc | 51 ++++- gold/fileread.h | 4 + gold/gold.cc | 2 +- gold/layout.cc | 8 +- gold/options.cc | 55 +++-- gold/options.h | 31 ++- gold/testsuite/Makefile.am | 13 ++ gold/testsuite/Makefile.in | 51 ++++- gold/testsuite/binary.in | 1 + gold/testsuite/binary_test.cc | 46 ++++ gold/testsuite/binary_unittest.cc | 147 ++++++++++++ 15 files changed, 849 insertions(+), 39 deletions(-) create mode 100644 gold/binary.cc create mode 100644 gold/binary.h create mode 100644 gold/testsuite/binary.in create mode 100644 gold/testsuite/binary_test.cc create mode 100644 gold/testsuite/binary_unittest.cc diff --git a/gold/Makefile.am b/gold/Makefile.am index 0f09afad60b..ea434584539 100644 --- a/gold/Makefile.am +++ b/gold/Makefile.am @@ -30,6 +30,7 @@ noinst_LIBRARIES = libgold.a CCFILES = \ archive.cc \ + binary.cc \ common.cc \ compressed_output.cc \ defstd.cc \ @@ -62,6 +63,7 @@ CCFILES = \ HFILES = \ archive.h \ + binary.h \ common.h \ compressed_output.h \ defstd.h \ diff --git a/gold/Makefile.in b/gold/Makefile.in index a315718e627..4e873520104 100644 --- a/gold/Makefile.in +++ b/gold/Makefile.in @@ -71,7 +71,7 @@ AR = ar ARFLAGS = cru libgold_a_AR = $(AR) $(ARFLAGS) libgold_a_LIBADD = -am__objects_1 = archive.$(OBJEXT) common.$(OBJEXT) \ +am__objects_1 = archive.$(OBJEXT) binary.$(OBJEXT) common.$(OBJEXT) \ compressed_output.$(OBJEXT) defstd.$(OBJEXT) \ dirsearch.$(OBJEXT) dynobj.$(OBJEXT) dwarf_reader.$(OBJEXT) \ ehframe.$(OBJEXT) errors.$(OBJEXT) expression.$(OBJEXT) \ @@ -299,6 +299,7 @@ AM_YFLAGS = -d noinst_LIBRARIES = libgold.a CCFILES = \ archive.cc \ + binary.cc \ common.cc \ compressed_output.cc \ defstd.cc \ @@ -331,6 +332,7 @@ CCFILES = \ HFILES = \ archive.h \ + binary.h \ common.h \ compressed_output.h \ defstd.h \ @@ -499,6 +501,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/pread.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/archive.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/binary.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/compressed_output.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/defstd.Po@am__quote@ diff --git a/gold/binary.cc b/gold/binary.cc new file mode 100644 index 00000000000..9909ff4e8ed --- /dev/null +++ b/gold/binary.cc @@ -0,0 +1,356 @@ +// binary.cc -- binary input files for gold + +// Copyright 2008 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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 +#include +#include "safe-ctype.h" + +#include "elfcpp.h" +#include "stringpool.h" +#include "fileread.h" +#include "output.h" +#include "binary.h" + +// Support for reading binary files as input. These become blobs in +// the final output. These files are treated as though they have a +// single .data section and define three symbols: +// _binary_FILENAME_start, _binary_FILENAME_end, _binary_FILENAME_end. +// The FILENAME is the name of the input file, with any +// non-alphanumeric character changed to an underscore. + +// We implement this by creating an ELF file in memory. + +namespace gold +{ + +// class Binary_to_elf. + +Binary_to_elf::Binary_to_elf(elfcpp::EM machine, int size, bool big_endian, + const std::string& filename) + : elf_machine_(machine), size_(size), big_endian_(big_endian), + filename_(filename), data_(NULL), filesize_(0) +{ +} + +Binary_to_elf::~Binary_to_elf() +{ + if (this->data_ != NULL) + delete[] this->data_; +} + +// Given FILENAME, create a buffer which looks like an ELF file with +// the contents of FILENAME as the contents of the only section. The +// TASK parameters is mainly for debugging, and records who holds +// locks. + +bool +Binary_to_elf::convert(const Task* task) +{ + if (this->size_ == 32) + { + if (!this->big_endian_) + { +#ifdef HAVE_TARGET_32_LITTLE + return this->sized_convert<32, false>(task); +#else + gold_unreachable(); +#endif + } + else + { +#ifdef HAVE_TARGET_32_BIG + return this->sized_convert<32, true>(task); +#else + gold_unreachable(); +#endif + } + } + else if (this->size_ == 64) + { + if (!this->big_endian_) + { +#ifdef HAVE_TARGET_64_LITTLE + return this->sized_convert<64, false>(task); +#else + gold_unreachable(); +#endif + } + else + { +#ifdef HAVE_TARGET_64_BIG + return this->sized_convert<64, true>(task); +#else + gold_unreachable(); +#endif + } + } + else + gold_unreachable(); +} + +// We are going to create: +// * The ELF file header. +// * Five sections: null section, .data, .symtab, .strtab, .shstrtab +// * The contents of the file. +// * Four symbols: null, begin, end, size. +// * Three symbol names. +// * Four section names. + +template +bool +Binary_to_elf::sized_convert(const Task* task) +{ + // Read the input file. + + File_read f; + if (!f.open(task, this->filename_)) + { + gold_error(_("cannot open %s: %s:"), this->filename_.c_str(), + strerror(errno)); + return false; + } + + section_size_type filesize = convert_to_section_size_type(f.filesize()); + const unsigned char* fileview = f.get_view(0, filesize, false); + + unsigned int align; + if (size == 32) + align = 4; + else if (size == 64) + align = 8; + else + gold_unreachable(); + section_size_type aligned_filesize = align_address(filesize, align); + + // Build the stringpool for the symbol table. + + std::string mangled_name = this->filename_; + for (std::string::iterator p = mangled_name.begin(); + p != mangled_name.end(); + ++p) + if (!ISALNUM(*p)) + *p = '_'; + mangled_name = "_binary_" + mangled_name; + std::string start_symbol_name = mangled_name + "_start"; + std::string end_symbol_name = mangled_name + "_end"; + std::string size_symbol_name = mangled_name + "_size"; + + Stringpool strtab; + strtab.add(start_symbol_name.c_str(), false, NULL); + strtab.add(end_symbol_name.c_str(), false, NULL); + strtab.add(size_symbol_name.c_str(), false, NULL); + strtab.set_string_offsets(); + + // Build the stringpool for the section name table. + + Stringpool shstrtab; + shstrtab.add(".data", false, NULL); + shstrtab.add(".symtab", false, NULL); + shstrtab.add(".strtab", false, NULL); + shstrtab.add(".shstrtab", false, NULL); + shstrtab.set_string_offsets(); + + // Work out the size of the generated file, and the offsets of the + // various sections, and allocate a buffer. + + const int sym_size = elfcpp::Elf_sizes::sym_size; + + size_t output_size = (elfcpp::Elf_sizes::ehdr_size + + 5 * elfcpp::Elf_sizes::shdr_size); + size_t data_offset = output_size; + output_size += aligned_filesize; + size_t symtab_offset = output_size; + output_size += 4 * sym_size; + size_t strtab_offset = output_size; + output_size += strtab.get_strtab_size(); + size_t shstrtab_offset = output_size; + output_size += shstrtab.get_strtab_size(); + + unsigned char* buffer = new unsigned char[output_size]; + + // Write out the data. + + unsigned char* pout = buffer; + + this->write_file_header(&pout); + + this->write_section_header("", &shstrtab, elfcpp::SHT_NULL, + 0, 0, 0, 0, 0, + 0, 0, &pout); + // Having the section be named ".data" and having it be writable is + // because th GNU linker does it that way, and existing linker + // script expect it. + this->write_section_header(".data", &shstrtab, + elfcpp::SHT_PROGBITS, + (elfcpp::SHF_ALLOC + | elfcpp::SHF_WRITE), + data_offset, + filesize, 0, 0, + align, 0, &pout); + this->write_section_header(".symtab", &shstrtab, + elfcpp::SHT_SYMTAB, + 0, symtab_offset, 4 * sym_size, + 3, 1, align, sym_size, &pout); + this->write_section_header(".strtab", &shstrtab, + elfcpp::SHT_STRTAB, + 0, strtab_offset, + strtab.get_strtab_size(), + 0, 0, 1, 0, &pout); + this->write_section_header(".shstrtab", &shstrtab, + elfcpp::SHT_STRTAB, + 0, shstrtab_offset, + shstrtab.get_strtab_size(), + 0, 0, 1, 0, &pout); + + memcpy(pout, fileview, filesize); + pout += filesize; + memset(pout, 0, aligned_filesize - filesize); + pout += aligned_filesize - filesize; + + this->write_symbol("", &strtab, 0, 0, &pout); + this->write_symbol(start_symbol_name, &strtab, 0, 1, + &pout); + this->write_symbol(end_symbol_name, &strtab, filesize, 1, + &pout); + this->write_symbol(size_symbol_name, &strtab, filesize, + elfcpp::SHN_ABS, &pout); + + strtab.write_to_buffer(pout, strtab.get_strtab_size()); + pout += strtab.get_strtab_size(); + + shstrtab.write_to_buffer(pout, shstrtab.get_strtab_size()); + pout += shstrtab.get_strtab_size(); + + gold_assert(static_cast(pout - buffer) == output_size); + + this->data_ = buffer; + this->filesize_ = output_size; + + f.unlock(task); + + return true; +} + +// Write out the file header. + +template +void +Binary_to_elf::write_file_header(unsigned char** ppout) +{ + elfcpp::Ehdr_write oehdr(*ppout); + + unsigned char e_ident[elfcpp::EI_NIDENT]; + memset(e_ident, 0, elfcpp::EI_NIDENT); + e_ident[elfcpp::EI_MAG0] = elfcpp::ELFMAG0; + e_ident[elfcpp::EI_MAG1] = elfcpp::ELFMAG1; + e_ident[elfcpp::EI_MAG2] = elfcpp::ELFMAG2; + e_ident[elfcpp::EI_MAG3] = elfcpp::ELFMAG3; + if (size == 32) + e_ident[elfcpp::EI_CLASS] = elfcpp::ELFCLASS32; + else if (size == 64) + e_ident[elfcpp::EI_CLASS] = elfcpp::ELFCLASS64; + else + gold_unreachable(); + e_ident[elfcpp::EI_DATA] = (big_endian + ? elfcpp::ELFDATA2MSB + : elfcpp::ELFDATA2LSB); + e_ident[elfcpp::EI_VERSION] = elfcpp::EV_CURRENT; + oehdr.put_e_ident(e_ident); + + oehdr.put_e_type(elfcpp::ET_REL); + oehdr.put_e_machine(this->elf_machine_); + oehdr.put_e_version(elfcpp::EV_CURRENT); + oehdr.put_e_entry(0); + oehdr.put_e_phoff(0); + oehdr.put_e_shoff(elfcpp::Elf_sizes::ehdr_size); + oehdr.put_e_flags(0); + oehdr.put_e_ehsize(elfcpp::Elf_sizes::ehdr_size); + oehdr.put_e_phentsize(0); + oehdr.put_e_phnum(0); + oehdr.put_e_shentsize(elfcpp::Elf_sizes::shdr_size); + oehdr.put_e_shnum(5); + oehdr.put_e_shstrndx(4); + + *ppout += elfcpp::Elf_sizes::ehdr_size; +} + +// Write out a section header. + +template +void +Binary_to_elf::write_section_header( + const char* name, + const Stringpool* shstrtab, + elfcpp::SHT type, + unsigned int flags, + section_size_type offset, + section_size_type section_size, + unsigned int link, + unsigned int info, + unsigned int addralign, + unsigned int entsize, + unsigned char** ppout) +{ + elfcpp::Shdr_write oshdr(*ppout); + + oshdr.put_sh_name(*name == '\0' ? 0 : shstrtab->get_offset(name)); + oshdr.put_sh_type(type); + oshdr.put_sh_flags(flags); + oshdr.put_sh_addr(0); + oshdr.put_sh_offset(offset); + oshdr.put_sh_size(section_size); + oshdr.put_sh_link(link); + oshdr.put_sh_info(info); + oshdr.put_sh_addralign(addralign); + oshdr.put_sh_entsize(entsize); + + *ppout += elfcpp::Elf_sizes::shdr_size; +} + +// Write out a symbol. + +template +void +Binary_to_elf::write_symbol( + const std::string& name, + const Stringpool* strtab, + section_size_type value, + unsigned int shndx, + unsigned char** ppout) +{ + unsigned char* pout = *ppout; + + elfcpp::Sym_write osym(pout); + osym.put_st_name(name.empty() ? 0 : strtab->get_offset(name.c_str())); + osym.put_st_value(value); + osym.put_st_size(0); + osym.put_st_info(name.empty() ? elfcpp::STB_LOCAL : elfcpp::STB_GLOBAL, + elfcpp::STT_NOTYPE); + osym.put_st_other(elfcpp::STV_DEFAULT, 0); + osym.put_st_shndx(shndx); + + *ppout += elfcpp::Elf_sizes::sym_size; +} + +} // End namespace gold. diff --git a/gold/binary.h b/gold/binary.h new file mode 100644 index 00000000000..75bc731e298 --- /dev/null +++ b/gold/binary.h @@ -0,0 +1,116 @@ +// binary.h -- binary input files for gold -*- C++ -*- + +// Copyright 2008 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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. + +// Support binary input files by making them look like an ELF file. + +#ifndef GOLD_BINARY_H +#define GOLD_BINARY_H + +#include + +#include "elfcpp.h" + +namespace gold +{ + +class Task; + +template +class Stringpool_template; + +// This class takes a file name and creates a buffer which looks like +// an ELF file read into memory. + +class Binary_to_elf +{ + public: + Binary_to_elf(elfcpp::EM machine, int size, bool big_endian, + const std::string& filename); + + ~Binary_to_elf(); + + // Read contents and create an ELF buffer. Return true if this + // succeeds, false otherwise. + bool + convert(const Task*); + + // Return a pointer to the contents of the ELF file. + const unsigned char* + converted_data() const + { return this->data_; } + + // Return a pointer to the contents of the ELF file and let the + // caller take charge of it. It was allocated using new[]. + unsigned char* + converted_data_leak() + { + unsigned char* ret = this->data_; + this->data_ = NULL; + return ret; + } + + // Return the size of the ELF file. + size_t + converted_size() const + { return this->filesize_; } + + private: + Binary_to_elf(const Binary_to_elf&); + Binary_to_elf& operator=(const Binary_to_elf&); + + template + bool + sized_convert(const Task*); + + template + void + write_file_header(unsigned char**); + + template + void + write_section_header(const char*, const Stringpool_template*, + elfcpp::SHT, unsigned int, section_size_type, + section_size_type, unsigned int, unsigned int, + unsigned int, unsigned int, unsigned char**); + + template + void + write_symbol(const std::string&, const Stringpool_template*, + section_size_type, unsigned int, unsigned char**); + + // The ELF machine code of the file to create. + elfcpp::EM elf_machine_; + // The size of the file to create, 32 or 64. + int size_; + // Whether to create a big endian file. + bool big_endian_; + // The name of the file to read. + std::string filename_; + // The ELF file data, allocated by new []. + unsigned char* data_; + // The ELF file size. + section_size_type filesize_; +}; + +} // End namespace gold. + +#endif // !defined(GOLD_BINARY_H) diff --git a/gold/fileread.cc b/gold/fileread.cc index c21c6eecd39..797b878b8ad 100644 --- a/gold/fileread.cc +++ b/gold/fileread.cc @@ -30,8 +30,11 @@ #include #include "filenames.h" +#include "parameters.h" #include "options.h" #include "dirsearch.h" +#include "target.h" +#include "binary.h" #include "fileread.h" namespace gold @@ -122,7 +125,7 @@ File_read::open(const Task* task, const std::string& name) return this->descriptor_ >= 0; } -// Open the file for testing purposes. +// Open the file with the contents in memory. bool File_read::open(const Task* task, const std::string& name, @@ -686,7 +689,19 @@ Input_file::open(const General_options& options, const Dirsearch& dirpath, } // Now that we've figured out where the file lives, try to open it. - if (!this->file_.open(task, name)) + + General_options::Object_format format = + this->input_argument_->options().input_format(); + bool ok; + if (format == General_options::OBJECT_FORMAT_ELF) + ok = this->file_.open(task, name); + else + { + gold_assert(format == General_options::OBJECT_FORMAT_BINARY); + ok = this->open_binary(task, name); + } + + if (!ok) { gold_error(_("cannot open %s: %s"), name.c_str(), strerror(errno)); @@ -696,4 +711,36 @@ Input_file::open(const General_options& options, const Dirsearch& dirpath, return true; } +// Open a file for --format binary. + +bool +Input_file::open_binary(const Task* task, const std::string& name) +{ + // In order to open a binary file, we need machine code, size, and + // endianness. If we have a target already, use it, otherwise use + // the defaults. + elfcpp::EM machine; + int size; + bool big_endian; + if (parameters->is_target_valid()) + { + Target* target = parameters->target(); + machine = target->machine_code(); + size = target->get_size(); + big_endian = target->is_big_endian(); + } + else + { + machine = elfcpp::GOLD_DEFAULT_MACHINE; + size = GOLD_DEFAULT_SIZE; + big_endian = GOLD_DEFAULT_BIG_ENDIAN; + } + + Binary_to_elf binary_to_elf(machine, size, big_endian, name); + if (!binary_to_elf.convert(task)) + return false; + return this->file_.open(task, name, binary_to_elf.converted_data_leak(), + binary_to_elf.converted_size()); +} + } // End namespace gold. diff --git a/gold/fileread.h b/gold/fileread.h index 2a9e797fc6b..33c1f091e1d 100644 --- a/gold/fileread.h +++ b/gold/fileread.h @@ -426,6 +426,10 @@ class Input_file Input_file(const Input_file&); Input_file& operator=(const Input_file&); + // Open a binary file. + bool + open_binary(const Task* task, const std::string& name); + // The argument from the command line. const Input_file_argument* input_argument_; // The name under which we opened the file. This is like the name diff --git a/gold/gold.cc b/gold/gold.cc index d09dee30866..1775db66cfb 100644 --- a/gold/gold.cc +++ b/gold/gold.cc @@ -196,7 +196,7 @@ queue_middle_tasks(const General_options& options, gold_error(_("cannot mix -r with dynamic object %s"), (*input_objects->dynobj_begin())->name().c_str()); if (!doing_static_link - && options.output_format() != General_options::OUTPUT_FORMAT_ELF) + && options.output_format() != General_options::OBJECT_FORMAT_ELF) gold_fatal(_("cannot use non-ELF output format with dynamic object %s"), (*input_objects->dynobj_begin())->name().c_str()); diff --git a/gold/layout.cc b/gold/layout.cc index cea25b0193e..6cba3aa3c3b 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -57,7 +57,7 @@ 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. Output_file* of = new Output_file(parameters->output_file_name()); - if (this->options_.output_format() != General_options::OUTPUT_FORMAT_ELF) + if (this->options_.output_format() != General_options::OBJECT_FORMAT_ELF) of->set_is_temporary(); of->open(file_size); @@ -951,7 +951,7 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab, else load_seg = this->find_first_load_seg(); - if (this->options_.output_format() != General_options::OUTPUT_FORMAT_ELF) + if (this->options_.output_format() != General_options::OBJECT_FORMAT_ELF) load_seg = NULL; gold_assert(phdr_seg == NULL || load_seg != NULL); @@ -2502,7 +2502,7 @@ void Layout::write_binary(Output_file* in) const { gold_assert(this->options_.output_format() - == General_options::OUTPUT_FORMAT_BINARY); + == General_options::OBJECT_FORMAT_BINARY); // Get the size of the binary file. uint64_t max_load_address = 0; @@ -2672,7 +2672,7 @@ void Close_task_runner::run(Workqueue*, const Task*) { // If we've been asked to create a binary file, we do so here. - if (this->options_->output_format() != General_options::OUTPUT_FORMAT_ELF) + if (this->options_->output_format() != General_options::OBJECT_FORMAT_ELF) this->layout_->write_binary(this->of_); this->of_->close(); diff --git a/gold/options.cc b/gold/options.cc index b660ed0cbb8..e83b78d6e5d 100644 --- a/gold/options.cc +++ b/gold/options.cc @@ -135,6 +135,29 @@ class options::Command_line_options namespace { +// Recognize input and output target names. The GNU linker accepts +// these with --format and --oformat. This code is intended to be +// minimally compatible. In practice for an ELF target this would be +// the same target as the input files; that name always start with +// "elf". Non-ELF targets would be "srec", "symbolsrec", "tekhex", +// "binary", "ihex". + +gold::General_options::Object_format +string_to_object_format(const char* arg) +{ + if (strncmp(arg, "elf", 3) == 0) + return gold::General_options::OBJECT_FORMAT_ELF; + else if (strcmp(arg, "binary") == 0) + return gold::General_options::OBJECT_FORMAT_BINARY; + else + { + gold::gold_error(_("format '%s' not supported " + "(supported formats: elf, binary)"), + arg); + return gold::General_options::OBJECT_FORMAT_ELF; + } +} + // Handle the special -l option, which adds an input file. int @@ -428,6 +451,9 @@ options::Command_line_options::options[] = &Position_dependent_options::set_static_search), GENERAL_NOARG('\0', "Bsymbolic", N_("Bind defined symbols locally"), NULL, ONE_DASH, &General_options::set_symbolic), + POSDEP_ARG('b', "format", N_("Set input format (elf, binary)"), + N_("-b FORMAT, --format FORMAT"), TWO_DASHES, + &Position_dependent_options::set_input_format), #ifdef HAVE_ZLIB_H # define ZLIB_STR ",zlib" #else @@ -608,7 +634,7 @@ General_options::General_options(Script_options* script_options) search_path_(), optimization_level_(0), output_file_name_("a.out"), - output_format_(OUTPUT_FORMAT_ELF), + output_format_(OBJECT_FORMAT_ELF), is_relocatable_(false), strip_(STRIP_NONE), allow_shlib_undefined_(false), @@ -647,22 +673,12 @@ General_options::define_symbol(const char* arg) this->script_options_->define_symbol(arg); } -// Handle the --oformat option. The GNU linker accepts a target name -// with --oformat. In practice for an ELF target this would be the -// same target as the input files. That name always start with "elf". -// Non-ELF targets would be "srec", "symbolsrec", "tekhex", "binary", -// "ihex". +// Handle the --oformat option. void General_options::set_output_format(const char* arg) { - if (strncmp(arg, "elf", 3) == 0) - this->output_format_ = OUTPUT_FORMAT_ELF; - else if (strcmp(arg, "binary") == 0) - this->output_format_ = OUTPUT_FORMAT_BINARY; - else - gold_error(_("format '%s' not supported (supported formats: elf, binary)"), - arg); + this->output_format_ = string_to_object_format(arg); } // Handle the -z option. @@ -738,8 +754,17 @@ General_options::add_sysroot() Position_dependent_options::Position_dependent_options() : do_static_search_(false), as_needed_(false), - include_whole_archive_(false) + include_whole_archive_(false), + input_format_(General_options::OBJECT_FORMAT_ELF) +{ +} + +// Set the input format. + +void +Position_dependent_options::set_input_format(const char* arg) { + this->input_format_ = string_to_object_format(arg); } // Search_directory methods. @@ -1045,7 +1070,7 @@ Command_line::normalize_options() if (this->options_.is_shared() && this->options_.is_relocatable()) gold_fatal(_("-shared and -r are incompatible")); - if (this->options_.output_format() != General_options::OUTPUT_FORMAT_ELF + if (this->options_.output_format() != General_options::OBJECT_FORMAT_ELF && (this->options_.is_shared() || this->options_.is_relocatable())) gold_fatal(_("binary output format not compatible with -shared or -r")); diff --git a/gold/options.h b/gold/options.h index 461a0626177..d62c2c26503 100644 --- a/gold/options.h +++ b/gold/options.h @@ -109,6 +109,14 @@ class Search_directory class General_options { public: + enum Object_format + { + // Ordinary ELF. + OBJECT_FORMAT_ELF, + // Straight binary format. + OBJECT_FORMAT_BINARY + }; + General_options(Script_options*); // -e: set entry address. @@ -150,15 +158,7 @@ class General_options // --oformat: Output format. - enum Output_format - { - // Ordinary ELF. - OUTPUT_FORMAT_ELF, - // Straight binary format. - OUTPUT_FORMAT_BINARY - }; - - Output_format + Object_format output_format() const { return this->output_format_; } @@ -561,7 +561,7 @@ class General_options Dir_list search_path_; int optimization_level_; const char* output_file_name_; - Output_format output_format_; + Object_format output_format_; bool is_relocatable_; Strip strip_; bool allow_shlib_undefined_; @@ -593,6 +593,8 @@ class General_options class Position_dependent_options { public: + typedef General_options::Object_format Object_format; + Position_dependent_options(); // -Bdynamic/-Bstatic: Whether we are searching for a static archive @@ -613,6 +615,11 @@ class Position_dependent_options include_whole_archive() const { return this->include_whole_archive_; } + // --format: The format of the input file. + Object_format + input_format() const + { return this->input_format_; } + void set_static_search() { this->do_static_search_ = true; } @@ -637,10 +644,14 @@ class Position_dependent_options clear_whole_archive() { this->include_whole_archive_ = false; } + void + set_input_format(const char*); + private: bool do_static_search_; bool as_needed_; bool include_whole_archive_; + Object_format input_format_; }; // A single file or library argument from the command line. diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am index c1a081c07df..0d1db37195c 100644 --- a/gold/testsuite/Makefile.am +++ b/gold/testsuite/Makefile.am @@ -53,6 +53,9 @@ LDADD = libgoldtest.a ../libgold.a ../../libiberty/libiberty.a $(LIBINTL) \ check_PROGRAMS += object_unittest object_unittest_SOURCES = object_unittest.cc +check_PROGRAMS += binary_unittest +binary_unittest_SOURCES = binary_unittest.cc + # --------------------------------------------------------------------- # These tests test the output of gold (end-to-end tests). In @@ -550,6 +553,16 @@ justsyms_2.o: justsyms_2.cc justsyms_2r.o: justsyms_2.o gcctestdir/ld gcctestdir/ld -o $@ -r -T $(srcdir)/justsyms.t justsyms_2.o +check_PROGRAMS += binary_test +binary_test_SOURCES = binary_test.cc +binary_test_DEPENDENCIES = gcctestdir/ld binary.txt +binary_test_LDFLAGS = -Bgcctestdir/ -Wl,--format,binary,binary.txt,--format,elf +# Copy the file to the build directory to avoid worrying about the +# full pathname in the generated symbols. +binary.txt: $(srcdir)/binary.in + rm -f $@ + $(LN_S) $< $@ + if OBJDUMP_AND_CPPFILT check_SCRIPTS += ver_matching_test.sh check_DATA += ver_matching_test.stdout diff --git a/gold/testsuite/Makefile.in b/gold/testsuite/Makefile.in index 10119ebc1ff..7b3a6c58380 100644 --- a/gold/testsuite/Makefile.in +++ b/gold/testsuite/Makefile.in @@ -42,10 +42,10 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ -check_PROGRAMS = object_unittest$(EXEEXT) $(am__EXEEXT_1) \ - $(am__EXEEXT_2) $(am__EXEEXT_3) $(am__EXEEXT_4) \ - $(am__EXEEXT_5) $(am__EXEEXT_6) $(am__EXEEXT_7) \ - $(am__EXEEXT_8) +check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \ + $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \ + $(am__EXEEXT_4) $(am__EXEEXT_5) $(am__EXEEXT_6) \ + $(am__EXEEXT_7) $(am__EXEEXT_8) @GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_1 = basic_test \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_static_test basic_pic_test \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_static_pic_test \ @@ -176,7 +176,8 @@ check_PROGRAMS = object_unittest$(EXEEXT) $(am__EXEEXT_1) \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ flagstest_o_specialfile \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ flagstest_o_specialfile_and_compress_debug_sections \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test script_test_1 \ -@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_2 justsyms +@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_2 justsyms \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ binary_test @GCC_FALSE@script_test_1_DEPENDENCIES = libgoldtest.a ../libgold.a \ @GCC_FALSE@ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \ @GCC_FALSE@ $(am__DEPENDENCIES_1) @@ -198,6 +199,13 @@ check_PROGRAMS = object_unittest$(EXEEXT) $(am__EXEEXT_1) \ @NATIVE_LINKER_FALSE@ ../libgold.a ../../libiberty/libiberty.a \ @NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \ @NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) +@GCC_FALSE@binary_test_DEPENDENCIES = libgoldtest.a ../libgold.a \ +@GCC_FALSE@ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \ +@GCC_FALSE@ $(am__DEPENDENCIES_1) +@NATIVE_LINKER_FALSE@binary_test_DEPENDENCIES = libgoldtest.a \ +@NATIVE_LINKER_FALSE@ ../libgold.a ../../libiberty/libiberty.a \ +@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \ +@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) @GCC_TRUE@@NATIVE_LINKER_TRUE@@OBJDUMP_AND_CPPFILT_TRUE@am__append_11 = ver_matching_test.sh \ @GCC_TRUE@@NATIVE_LINKER_TRUE@@OBJDUMP_AND_CPPFILT_TRUE@ script_test_3.sh @GCC_TRUE@@NATIVE_LINKER_TRUE@@OBJDUMP_AND_CPPFILT_TRUE@am__append_12 = ver_matching_test.stdout \ @@ -272,7 +280,8 @@ libgoldtest_a_OBJECTS = $(am_libgoldtest_a_OBJECTS) @GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test$(EXEEXT) \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_1$(EXEEXT) \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_2$(EXEEXT) \ -@GCC_TRUE@@NATIVE_LINKER_TRUE@ justsyms$(EXEEXT) +@GCC_TRUE@@NATIVE_LINKER_TRUE@ justsyms$(EXEEXT) \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ binary_test$(EXEEXT) @GCC_TRUE@@NATIVE_LINKER_TRUE@@OBJDUMP_AND_CPPFILT_TRUE@am__EXEEXT_8 = script_test_3$(EXEEXT) basic_pic_test_SOURCES = basic_pic_test.c basic_pic_test_OBJECTS = basic_pic_test.$(OBJEXT) @@ -299,6 +308,17 @@ basic_test_LDADD = $(LDADD) basic_test_DEPENDENCIES = libgoldtest.a ../libgold.a \ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) +am__binary_test_SOURCES_DIST = binary_test.cc +@GCC_TRUE@@NATIVE_LINKER_TRUE@am_binary_test_OBJECTS = \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ binary_test.$(OBJEXT) +binary_test_OBJECTS = $(am_binary_test_OBJECTS) +binary_test_LDADD = $(LDADD) +am_binary_unittest_OBJECTS = binary_unittest.$(OBJEXT) +binary_unittest_OBJECTS = $(am_binary_unittest_OBJECTS) +binary_unittest_LDADD = $(LDADD) +binary_unittest_DEPENDENCIES = libgoldtest.a ../libgold.a \ + ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) am__constructor_static_test_SOURCES_DIST = constructor_test.cc @GCC_TRUE@@NATIVE_LINKER_TRUE@am__objects_1 = \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ constructor_test.$(OBJEXT) @@ -577,6 +597,7 @@ CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ -o $@ SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c \ basic_static_pic_test.c basic_static_test.c basic_test.c \ + $(binary_test_SOURCES) $(binary_unittest_SOURCES) \ $(constructor_static_test_SOURCES) $(constructor_test_SOURCES) \ $(exception_same_shared_test_SOURCES) \ $(exception_separate_shared_12_test_SOURCES) \ @@ -612,6 +633,7 @@ SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c \ $(ver_test_SOURCES) $(weak_test_SOURCES) DIST_SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c \ basic_static_pic_test.c basic_static_test.c basic_test.c \ + $(am__binary_test_SOURCES_DIST) $(binary_unittest_SOURCES) \ $(am__constructor_static_test_SOURCES_DIST) \ $(am__constructor_test_SOURCES_DIST) \ $(am__exception_same_shared_test_SOURCES_DIST) \ @@ -826,6 +848,7 @@ LDADD = libgoldtest.a ../libgold.a ../../libiberty/libiberty.a $(LIBINTL) \ $(THREADSLIB) object_unittest_SOURCES = object_unittest.cc +binary_unittest_SOURCES = binary_unittest.cc @GCC_TRUE@@NATIVE_LINKER_TRUE@constructor_test_SOURCES = constructor_test.cc @GCC_TRUE@@NATIVE_LINKER_TRUE@constructor_test_DEPENDENCIES = gcctestdir/ld @GCC_TRUE@@NATIVE_LINKER_TRUE@constructor_test_LDFLAGS = -Bgcctestdir/ @@ -1025,6 +1048,9 @@ object_unittest_SOURCES = object_unittest.cc @GCC_TRUE@@NATIVE_LINKER_TRUE@justsyms_SOURCES = justsyms_1.cc @GCC_TRUE@@NATIVE_LINKER_TRUE@justsyms_DEPENDENCIES = gcctestdir/ld justsyms_2r.o @GCC_TRUE@@NATIVE_LINKER_TRUE@justsyms_LDFLAGS = -Bgcctestdir/ -Wl,-R,justsyms_2r.o +@GCC_TRUE@@NATIVE_LINKER_TRUE@binary_test_SOURCES = binary_test.cc +@GCC_TRUE@@NATIVE_LINKER_TRUE@binary_test_DEPENDENCIES = gcctestdir/ld binary.txt +@GCC_TRUE@@NATIVE_LINKER_TRUE@binary_test_LDFLAGS = -Bgcctestdir/ -Wl,--format,binary,binary.txt,--format,elf all: all-am .SUFFIXES: @@ -1092,6 +1118,12 @@ clean-checkPROGRAMS: @NATIVE_LINKER_FALSE@basic_test$(EXEEXT): $(basic_test_OBJECTS) $(basic_test_DEPENDENCIES) @NATIVE_LINKER_FALSE@ @rm -f basic_test$(EXEEXT) @NATIVE_LINKER_FALSE@ $(LINK) $(basic_test_LDFLAGS) $(basic_test_OBJECTS) $(basic_test_LDADD) $(LIBS) +binary_test$(EXEEXT): $(binary_test_OBJECTS) $(binary_test_DEPENDENCIES) + @rm -f binary_test$(EXEEXT) + $(CXXLINK) $(binary_test_LDFLAGS) $(binary_test_OBJECTS) $(binary_test_LDADD) $(LIBS) +binary_unittest$(EXEEXT): $(binary_unittest_OBJECTS) $(binary_unittest_DEPENDENCIES) + @rm -f binary_unittest$(EXEEXT) + $(CXXLINK) $(binary_unittest_LDFLAGS) $(binary_unittest_OBJECTS) $(binary_unittest_LDADD) $(LIBS) constructor_static_test$(EXEEXT): $(constructor_static_test_OBJECTS) $(constructor_static_test_DEPENDENCIES) @rm -f constructor_static_test$(EXEEXT) $(CXXLINK) $(constructor_static_test_LDFLAGS) $(constructor_static_test_OBJECTS) $(constructor_static_test_LDADD) $(LIBS) @@ -1250,6 +1282,8 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/basic_static_pic_test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/basic_static_test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/basic_test.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/binary_test.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/binary_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/constructor_test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exception_test_1.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exception_test_2.Po@am__quote@ @@ -1718,6 +1752,11 @@ uninstall-am: uninstall-info-am @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -o $@ $< @GCC_TRUE@@NATIVE_LINKER_TRUE@justsyms_2r.o: justsyms_2.o gcctestdir/ld @GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld -o $@ -r -T $(srcdir)/justsyms.t justsyms_2.o +# Copy the file to the build directory to avoid worrying about the +# full pathname in the generated symbols. +@GCC_TRUE@@NATIVE_LINKER_TRUE@binary.txt: $(srcdir)/binary.in +@GCC_TRUE@@NATIVE_LINKER_TRUE@ rm -f $@ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(LN_S) $< $@ @GCC_TRUE@@NATIVE_LINKER_TRUE@@OBJDUMP_AND_CPPFILT_TRUE@ver_matching_def.so: ver_matching_def.cc gcctestdir/ld @GCC_TRUE@@NATIVE_LINKER_TRUE@@OBJDUMP_AND_CPPFILT_TRUE@ $(CXXLINK) -O0 -Bgcctestdir/ -shared $(srcdir)/ver_matching_def.cc -Wl,--version-script=$(srcdir)/version_script.map @GCC_TRUE@@NATIVE_LINKER_TRUE@@OBJDUMP_AND_CPPFILT_TRUE@ver_matching_test.stdout: ver_matching_def.so diff --git a/gold/testsuite/binary.in b/gold/testsuite/binary.in new file mode 100644 index 00000000000..cf5d6319d48 --- /dev/null +++ b/gold/testsuite/binary.in @@ -0,0 +1 @@ +This file is used for the binary test. diff --git a/gold/testsuite/binary_test.cc b/gold/testsuite/binary_test.cc new file mode 100644 index 00000000000..d645536f1f7 --- /dev/null +++ b/gold/testsuite/binary_test.cc @@ -0,0 +1,46 @@ +// binary_test.cc -- test --format binary for gold + +// Copyright 2008 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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. + +// This program is linked with a small text file named binary.txt +// using --formatbinary. + +#include +#include +#include +#include + +extern char _binary_binary_txt_start[]; +extern char _binary_binary_txt_end[]; +extern char _binary_binary_txt_size[]; + +int +main(int, char**) +{ + int size = reinterpret_cast(_binary_binary_txt_size); + assert(size == _binary_binary_txt_end - _binary_binary_txt_start); + + const char* const txt = "This file is used for the binary test.\n"; + assert(strncmp(txt, _binary_binary_txt_start, size) == 0); + assert(static_cast(size) == strlen(txt)); + + return 0; +} diff --git a/gold/testsuite/binary_unittest.cc b/gold/testsuite/binary_unittest.cc new file mode 100644 index 00000000000..0be2478a8bf --- /dev/null +++ b/gold/testsuite/binary_unittest.cc @@ -0,0 +1,147 @@ +// binary_unittest.cc -- test Binary_to_elf + +// Copyright 2008 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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 +#include +#include +#include + +#include "elfcpp.h" +#include "parameters.h" +#include "errors.h" +#include "options.h" +#include "binary.h" +#include "object.h" + +#include "test.h" +#include "testfile.h" + +namespace gold_testsuite +{ + +using namespace gold; + +template +bool +Sized_binary_test(Target* target) +{ + // We need a pretend Task. + const Task* task = reinterpret_cast(-1); + + // Use the executable itself as the binary data. + struct stat st; + CHECK(::stat(gold::program_name, &st) == 0); + int o = ::open(gold::program_name, O_RDONLY); + CHECK(o >= 0); + unsigned char* filedata = new unsigned char[st.st_size]; + CHECK(::read(o, filedata, st.st_size) == st.st_size); + CHECK(::close(o) == 0); + + Binary_to_elf binary(static_cast(0xffff), size, big_endian, + gold::program_name); + + CHECK(binary.convert(task)); + + Input_file input_file(task, "test.o", binary.converted_data(), + binary.converted_size()); + Object* object = make_elf_object("test.o", &input_file, 0, + binary.converted_data(), + binary.converted_size()); + CHECK(object != NULL); + if (object == NULL) + return false; + + CHECK(!object->is_dynamic()); + CHECK(object->target() == target); + CHECK(object->shnum() == 5); + CHECK(object->section_name(1) == ".data"); + CHECK(object->section_flags(1) == elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE); + section_size_type len; + const unsigned char* contents = object->section_contents(1, &len, false); + CHECK(len == st.st_size); + CHECK(memcmp(filedata, contents, len) == 0); + + // Force the symbols to be read internally, so that + // symbol_section_and_value will work. + Read_symbols_data sd; + object->read_symbols(&sd); + delete sd.section_headers; + delete sd.section_names; + delete sd.symbols; + delete sd.symbol_names; + + Sized_relobj* relobj = + static_cast*>(object); + typename Sized_relobj::Address value; + CHECK(relobj->symbol_section_and_value(0, &value) == 0); + CHECK(value == 0); + CHECK(relobj->symbol_section_and_value(1, &value) == 1); + CHECK(value == 0); + CHECK(relobj->symbol_section_and_value(2, &value) == 1); + CHECK(static_cast(value) == st.st_size); + CHECK(relobj->symbol_section_and_value(3, &value) == elfcpp::SHN_ABS); + CHECK(static_cast(value) == st.st_size); + + object->unlock(task); + return true; +} + +bool +Binary_test(Test_report*) +{ + Errors errors(gold::program_name); + initialize_parameters(&errors); + + Script_options script_options; + General_options options(&script_options); + set_parameters_from_options(&options); + + int fail = 0; + +#ifdef HAVE_TARGET_32_LITTLE + if (!Sized_binary_test<32, false>(target_test_pointer_32_little)) + ++fail; +#endif + +#ifdef HAVE_TARGET_32_BIG + if (!Sized_binary_test<32, true>(target_test_pointer_32_big)) + ++fail; +#endif + +#ifdef HAVE_TARGET_64_LITTLE + if (!Sized_binary_test<64, false>(target_test_pointer_64_little)) + ++fail; +#endif + +#ifdef HAVE_TARGET_64_BIG + if (!Sized_binary_test<64, true>(target_test_pointer_64_big)) + ++fail; +#endif + + return fail == 0; +} + +Register_test binary_register("Binary", Binary_test); + +} // End namespace gold_testsuite. -- 2.30.2