X-Git-Url: https://oss.titaniummirror.com/gitweb?p=msp430-binutils.git;a=blobdiff_plain;f=gold%2Ffreebsd.h;fp=gold%2Ffreebsd.h;h=de697357f41f1bb10d89f857bf178f7924d49bc5;hp=0000000000000000000000000000000000000000;hb=d5da4f291af551c0b8b79e1d4a9b173d60e5c10e;hpb=7b5ea4fcdf2819e070665ab5610f8b48e3867c10 diff --git a/gold/freebsd.h b/gold/freebsd.h new file mode 100644 index 0000000..de69735 --- /dev/null +++ b/gold/freebsd.h @@ -0,0 +1,168 @@ +// freebsd.h -- FreeBSD support for gold -*- C++ -*- + +// Copyright 2009 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 "target.h" +#include "target-select.h" + +#ifndef GOLD_FREEBSD_H +#define GOLD_FREEBSD_H + +namespace gold +{ + +// FreeBSD 4.1 and later wants the EI_OSABI field in the ELF header to +// be set to ELFOSABI_FREEBSD. This is a subclass of Sized_target +// which supports that. The real target would be a subclass of this +// one. We permit combining FreeBSD and non-FreeBSD object files. +// The effect of this target is to set the code in the output file. + +template +class Target_freebsd : public Sized_target +{ + public: + // Set the value to use for the EI_OSABI field in the ELF header. + void + set_osabi(elfcpp::ELFOSABI osabi) + { this->osabi_ = osabi; } + + protected: + Target_freebsd(const Target::Target_info* pti) + : Sized_target(pti), + osabi_(elfcpp::ELFOSABI_NONE) + { } + + virtual void + do_adjust_elf_header(unsigned char* view, int len) const; + + private: + // Value to store in the EI_OSABI field of the ELF file header. + elfcpp::ELFOSABI osabi_; +}; + +// Adjust the ELF file header by storing the requested value in the +// OSABI field. This is for FreeBSD support. + +template +inline void +Target_freebsd::do_adjust_elf_header(unsigned char* view, + int len) const +{ + if (this->osabi_ != elfcpp::ELFOSABI_NONE) + { + gold_assert(len == elfcpp::Elf_sizes::ehdr_size); + + elfcpp::Ehdr ehdr(view); + unsigned char e_ident[elfcpp::EI_NIDENT]; + memcpy(e_ident, ehdr.get_e_ident(), elfcpp::EI_NIDENT); + + e_ident[elfcpp::EI_OSABI] = this->osabi_; + + elfcpp::Ehdr_write oehdr(view); + oehdr.put_e_ident(e_ident); + } +} + +// A target selector for targets which permit combining both FreeBSD +// and non-FreeBSD object files. + +class Target_selector_freebsd : public Target_selector +{ + public: + Target_selector_freebsd(int machine, int size, bool is_big_endian, + const char* bfd_name, + const char* freebsd_bfd_name) + : Target_selector(machine, size, is_big_endian, NULL), + bfd_name_(bfd_name), freebsd_bfd_name_(freebsd_bfd_name) + { } + + protected: + // If we see a FreeBSD input file, mark the output file as using + // FreeBSD. + virtual Target* + do_recognize(int, int osabi, int) + { + Target* ret = this->instantiate_target(); + if (osabi == elfcpp::ELFOSABI_FREEBSD) + this->set_osabi(ret); + return ret; + } + + // Recognize two names. + virtual Target* + do_recognize_by_name(const char* name) + { + if (strcmp(name, this->bfd_name_) == 0) + return this->instantiate_target(); + else if (strcmp(name, this->freebsd_bfd_name_) == 0) + { + Target* ret = this->instantiate_target(); + this->set_osabi(ret); + return ret; + } + else + return NULL; + } + + // Print both names in --help output. + virtual void + do_supported_names(std::vector* names) + { + names->push_back(this->bfd_name_); + names->push_back(this->freebsd_bfd_name_); + } + + private: + // Set the OSABI field. This is quite ugly. + void + set_osabi(Target* target) + { + if (this->get_size() == 32) + { + if (this->is_big_endian()) + static_cast*>(target)-> + set_osabi(elfcpp::ELFOSABI_FREEBSD); + else + static_cast*>(target)-> + set_osabi(elfcpp::ELFOSABI_FREEBSD); + } + else if (this->get_size() == 64) + { + if (this->is_big_endian()) + static_cast*>(target)-> + set_osabi(elfcpp::ELFOSABI_FREEBSD); + else + static_cast*>(target)-> + set_osabi(elfcpp::ELFOSABI_FREEBSD); + } + else + gold_unreachable(); + } + + // The BFD name for the non-Freebsd target. + const char* bfd_name_; + // The BFD name for the Freebsd target. + const char* freebsd_bfd_name_; +}; + +} // end namespace gold + +#endif // !defined(GOLD_FREEBSD_H)