Commit | Line | Data |
---|---|---|
36959681 ILT |
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 | ||
29 | namespace 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 | ||
38 | template<int size, bool big_endian> | |
39 | class 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 | ||
64 | template<int size, bool big_endian> | |
65 | inline void | |
66 | Target_freebsd<size, big_endian>::do_adjust_elf_header(unsigned char* view, | |
67 | int len) const | |
68 | { | |
69 | if (this->osabi_ != elfcpp::ELFOSABI_NONE) | |
70 | { | |
c9d70757 | 71 | gold_assert(len == elfcpp::Elf_sizes<size>::ehdr_size); |
36959681 | 72 | |
c9d70757 | 73 | elfcpp::Ehdr<size, false> ehdr(view); |
36959681 ILT |
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 | ||
c9d70757 | 79 | elfcpp::Ehdr_write<size, false> oehdr(view); |
36959681 ILT |
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 | ||
87 | class 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) |