1// freebsd.h -- FreeBSD support for gold -*- C++ -*- 2 3// Copyright 2009 Free Software Foundation, Inc. 4// Written by Ian Lance Taylor <iant@google.com>. 5 6// This file is part of gold. 7 8// This program is free software; you can redistribute it and/or modify 9// it under the terms of the GNU General Public License as published by 10// the Free Software Foundation; either version 3 of the License, or 11// (at your option) any later version. 12 13// This program is distributed in the hope that it will be useful, 14// but WITHOUT ANY WARRANTY; without even the implied warranty of 15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16// GNU General Public License for more details. 17 18// You should have received a copy of the GNU General Public License 19// along with this program; if not, write to the Free Software 20// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 21// MA 02110-1301, USA. 22 23#include "target.h" 24#include "target-select.h" 25 26#ifndef GOLD_FREEBSD_H 27#define GOLD_FREEBSD_H 28 29namespace gold 30{ 31 32// FreeBSD 4.1 and later wants the EI_OSABI field in the ELF header to 33// be set to ELFOSABI_FREEBSD. This is a subclass of Sized_target 34// which supports that. The real target would be a subclass of this 35// one. We permit combining FreeBSD and non-FreeBSD object files. 36// The effect of this target is to set the code in the output file. 37 38template<int size, bool big_endian> 39class Target_freebsd : public Sized_target<size, big_endian> 40{ 41 public: 42 // Set the value to use for the EI_OSABI field in the ELF header. 43 void 44 set_osabi(elfcpp::ELFOSABI osabi) 45 { this->osabi_ = osabi; } 46 47 protected: 48 Target_freebsd(const Target::Target_info* pti) 49 : Sized_target<size, big_endian>(pti), 50 osabi_(elfcpp::ELFOSABI_NONE) 51 { } 52 53 virtual void 54 do_adjust_elf_header(unsigned char* view, int len) const; 55 56 private: 57 // Value to store in the EI_OSABI field of the ELF file header. 58 elfcpp::ELFOSABI osabi_; 59}; 60 61// Adjust the ELF file header by storing the requested value in the 62// OSABI field. This is for FreeBSD support. 63 64template<int size, bool big_endian> 65inline void 66Target_freebsd<size, big_endian>::do_adjust_elf_header(unsigned char* view, 67 int len) const 68{ 69 if (this->osabi_ != elfcpp::ELFOSABI_NONE) 70 { 71 gold_assert(len == elfcpp::Elf_sizes<size>::ehdr_size); 72 73 elfcpp::Ehdr<size, false> ehdr(view); 74 unsigned char e_ident[elfcpp::EI_NIDENT]; 75 memcpy(e_ident, ehdr.get_e_ident(), elfcpp::EI_NIDENT); 76 77 e_ident[elfcpp::EI_OSABI] = this->osabi_; 78 79 elfcpp::Ehdr_write<size, false> oehdr(view); 80 oehdr.put_e_ident(e_ident); 81 } 82} 83 84// A target selector for targets which permit combining both FreeBSD 85// and non-FreeBSD object files. 86 87class Target_selector_freebsd : public Target_selector 88{ 89 public: 90 Target_selector_freebsd(int machine, int size, bool is_big_endian, 91 const char* bfd_name, 92 const char* freebsd_bfd_name) 93 : Target_selector(machine, size, is_big_endian, NULL), 94 bfd_name_(bfd_name), freebsd_bfd_name_(freebsd_bfd_name) 95 { } 96 97 protected: 98 // If we see a FreeBSD input file, mark the output file as using 99 // FreeBSD. 100 virtual Target* 101 do_recognize(int, int osabi, int) 102 { 103 Target* ret = this->instantiate_target(); 104 if (osabi == elfcpp::ELFOSABI_FREEBSD) 105 this->set_osabi(ret); 106 return ret; 107 } 108 109 // Recognize two names. 110 virtual Target* 111 do_recognize_by_name(const char* name) 112 { 113 if (strcmp(name, this->bfd_name_) == 0) 114 return this->instantiate_target(); 115 else if (strcmp(name, this->freebsd_bfd_name_) == 0) 116 { 117 Target* ret = this->instantiate_target(); 118 this->set_osabi(ret); 119 return ret; 120 } 121 else 122 return NULL; 123 } 124 125 // Print both names in --help output. 126 virtual void 127 do_supported_names(std::vector<const char*>* names) 128 { 129 names->push_back(this->bfd_name_); 130 names->push_back(this->freebsd_bfd_name_); 131 } 132 133 private: 134 // Set the OSABI field. This is quite ugly. 135 void 136 set_osabi(Target* target) 137 { 138 if (this->get_size() == 32) 139 { 140 if (this->is_big_endian()) 141 static_cast<Target_freebsd<32, true>*>(target)-> 142 set_osabi(elfcpp::ELFOSABI_FREEBSD); 143 else 144 static_cast<Target_freebsd<32, false>*>(target)-> 145 set_osabi(elfcpp::ELFOSABI_FREEBSD); 146 } 147 else if (this->get_size() == 64) 148 { 149 if (this->is_big_endian()) 150 static_cast<Target_freebsd<64, true>*>(target)-> 151 set_osabi(elfcpp::ELFOSABI_FREEBSD); 152 else 153 static_cast<Target_freebsd<64, false>*>(target)-> 154 set_osabi(elfcpp::ELFOSABI_FREEBSD); 155 } 156 else 157 gold_unreachable(); 158 } 159 160 // The BFD name for the non-Freebsd target. 161 const char* bfd_name_; 162 // The BFD name for the Freebsd target. 163 const char* freebsd_bfd_name_; 164}; 165 166} // end namespace gold 167 168#endif // !defined(GOLD_FREEBSD_H) 169