| // attributes.cc -- object attributes for gold | |
| // Copyright (C) 2009-2017 Free Software Foundation, Inc. | |
| // Written by Doug Kwan <dougkwan@google.com>. | |
| // This file contains code adapted from BFD. | |
| // 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 <limits> | |
| #include "attributes.h" | |
| #include "elfcpp.h" | |
| #include "target.h" | |
| #include "parameters.h" | |
| #include "int_encoding.h" | |
| namespace gold | |
| { | |
| // Object_attribute methods. | |
| // Return size of attribute encode in ULEB128. | |
| size_t | |
| Object_attribute::size(int tag) const | |
| { | |
| // Attributes with default values are not written out. | |
| if (this->is_default_attribute()) | |
| return 0; | |
| size_t size = get_length_as_unsigned_LEB_128(tag); | |
| if (Object_attribute::attribute_type_has_int_value(this->type_)) | |
| size += get_length_as_unsigned_LEB_128(this->int_value_); | |
| if (Object_attribute::attribute_type_has_string_value(this->type_)) | |
| size += this->string_value_.size() + 1; | |
| return size; | |
| } | |
| // Whether this has the default value (0/""). | |
| bool | |
| Object_attribute::is_default_attribute() const | |
| { | |
| if (Object_attribute::attribute_type_has_int_value(this->type_) | |
| && this->int_value_ != 0) | |
| return false; | |
| if (Object_attribute::attribute_type_has_string_value(this->type_) | |
| && !this->string_value_.empty()) | |
| return false; | |
| if (Object_attribute::attribute_type_has_no_default(this->type_)) | |
| return false; | |
| return true; | |
| } | |
| // Whether this matches another Object_attribute OA in merging. | |
| // Two Object_attributes match if they have the same values. | |
| bool | |
| Object_attribute::matches(const Object_attribute& oa) const | |
| { | |
| return ((this->int_value_ != oa.int_value_) | |
| && (this->string_value_ == oa.string_value_)); | |
| } | |
| // Write this with TAG to a BUFFER. | |
| void | |
| Object_attribute::write( | |
| int tag, | |
| std::vector<unsigned char>* buffer) const | |
| { | |
| // No need to write default attributes. | |
| if (this->is_default_attribute()) | |
| return; | |
| // Write tag. | |
| write_unsigned_LEB_128(buffer, convert_types<uint64_t, int>(tag)); | |
| // Write integer value. | |
| if (Object_attribute::attribute_type_has_int_value(this->type_)) | |
| write_unsigned_LEB_128(buffer, | |
| convert_types<uint64_t, int>(this->int_value_)); | |
| // Write string value. | |
| if (Object_attribute::attribute_type_has_string_value(this->type_)) | |
| { | |
| const unsigned char* start = | |
| reinterpret_cast<const unsigned char*>(this->string_value_.c_str()); | |
| const unsigned char* end = start + this->string_value_.size() + 1; | |
| buffer->insert(buffer->end(), start, end); | |
| } | |
| } | |
| // Vendor_object_attributes methods. | |
| // Copying constructor. | |
| Vendor_object_attributes::Vendor_object_attributes( | |
| const Vendor_object_attributes& voa) | |
| { | |
| this->vendor_ = voa.vendor_; | |
| for (int i = 0; i < NUM_KNOWN_ATTRIBUTES; ++i) | |
| this->known_attributes_[i] = voa.known_attributes_[i]; | |
| // We do not handle attribute deletion. So this must be empty. | |
| gold_assert(this->other_attributes_.empty()); | |
| for (Other_attributes::const_iterator p = voa.other_attributes_.begin(); | |
| p != voa.other_attributes_.end(); | |
| ++p) | |
| this->other_attributes_[p->first] = new Object_attribute(*(p->second)); | |
| } | |
| // Size of this in number of bytes. | |
| size_t | |
| Vendor_object_attributes::size() const | |
| { | |
| if (this->name() == NULL) | |
| return 0; | |
| size_t data_size = 0; | |
| for (int i = 4; i < NUM_KNOWN_ATTRIBUTES; ++i) | |
| data_size += this->known_attributes_[i].size(i); | |
| for (Other_attributes::const_iterator p = this->other_attributes_.begin(); | |
| p != this->other_attributes_.end(); | |
| ++p) | |
| data_size += p->second->size(p->first); | |
| // <size> <vendor_name> NUL 0x1 <size> | |
| return ((data_size != 0 | |
| || this->vendor_ == Object_attribute::OBJ_ATTR_PROC) | |
| ? data_size + strlen(this->name()) + 2 + 2 * 4 | |
| : 0); | |
| } | |
| // Return a new attribute associated with TAG. | |
| Object_attribute* | |
| Vendor_object_attributes::new_attribute(int tag) | |
| { | |
| int type = Object_attribute::arg_type(this->vendor_, tag); | |
| if (tag < NUM_KNOWN_ATTRIBUTES) | |
| { | |
| this->known_attributes_[tag].set_type(type); | |
| return &this->known_attributes_[tag]; | |
| } | |
| else | |
| { | |
| Object_attribute* attr = new Object_attribute(); | |
| // This should be the first time we insert this. | |
| std::pair<Other_attributes::iterator, bool> ins = | |
| this->other_attributes_.insert(std::make_pair(tag, attr)); | |
| gold_assert(ins.second); | |
| attr->set_type(type); | |
| return attr; | |
| } | |
| } | |
| // Return an attribute associated with TAG. | |
| Object_attribute* | |
| Vendor_object_attributes::get_attribute(int tag) | |
| { | |
| if (tag < NUM_KNOWN_ATTRIBUTES) | |
| return &this->known_attributes_[tag]; | |
| else | |
| { | |
| Other_attributes::iterator p = | |
| this->other_attributes_.find(tag); | |
| return p != this->other_attributes_.end() ? p->second : NULL; | |
| } | |
| } | |
| const Object_attribute* | |
| Vendor_object_attributes::get_attribute(int tag) const | |
| { | |
| if (tag < NUM_KNOWN_ATTRIBUTES) | |
| return &this->known_attributes_[tag]; | |
| else | |
| { | |
| Other_attributes::const_iterator p = | |
| this->other_attributes_.find(tag); | |
| return p != this->other_attributes_.end() ? p->second : NULL; | |
| } | |
| } | |
| // Write attributes to BUFFER. | |
| void | |
| Vendor_object_attributes::write(std::vector<unsigned char>* buffer) const | |
| { | |
| // Write subsection size. | |
| size_t voa_size = this->size(); | |
| uint32_t voa_size_as_u32 = convert_types<uint32_t, size_t>(voa_size); | |
| insert_into_vector<32>(buffer, voa_size_as_u32); | |
| // Write vendor name. | |
| const unsigned char* vendor_start = | |
| reinterpret_cast<const unsigned char*>(this->name()); | |
| size_t vendor_length = strlen(this->name()) + 1; | |
| const unsigned char* vendor_end = vendor_start + vendor_length; | |
| buffer->insert(buffer->end(), vendor_start, vendor_end); | |
| // Write file tag. | |
| buffer->push_back(Object_attribute::Tag_File); | |
| // Write attributes size. | |
| uint32_t attributes_size_as_u32 = | |
| convert_types<uint32_t, size_t>(voa_size - 4 - vendor_length); | |
| insert_into_vector<32>(buffer, attributes_size_as_u32); | |
| // Write known attributes, skipping any defaults. | |
| for (int i = 4; i < NUM_KNOWN_ATTRIBUTES; ++i) | |
| { | |
| // A target may write known attributes in a special order. | |
| // Call target hook to remap tags. Attributes_order is the identity | |
| // function if no re-ordering is required. | |
| int tag = parameters->target().attributes_order(i); | |
| this->known_attributes_[tag].write(tag, buffer); | |
| } | |
| // Write other attributes. | |
| for (Other_attributes::const_iterator q = this->other_attributes_.begin(); | |
| q != this->other_attributes_.end(); | |
| ++q) | |
| q->second->write(q->first, buffer); | |
| } | |
| // Attributes_section_data methods. | |
| // Compute encoded size of this. | |
| size_t | |
| Attributes_section_data::size() const | |
| { | |
| size_t data_size = 0; | |
| for(int vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; ++vendor) | |
| data_size += this->vendor_object_attributes_[vendor]->size(); | |
| // 'A' <sections for each vendor> | |
| return data_size != 0 ? data_size + 1 : 0; | |
| } | |
| // Construct an Attributes_section_data object by parsing section contents | |
| // specified by VIEW and SIZE. | |
| Attributes_section_data::Attributes_section_data( | |
| const unsigned char* view, | |
| section_size_type size) | |
| { | |
| for (int vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; ++vendor) | |
| this->vendor_object_attributes_[vendor] = | |
| new Vendor_object_attributes(vendor); | |
| const unsigned char* p = view; | |
| p = view; | |
| if (size > 0 && p != NULL && *(p++) == 'A') | |
| { | |
| size--; | |
| while (size > 0) | |
| { | |
| // Size of vendor attributes section. | |
| section_size_type section_size = | |
| convert_to_section_size_type(read_from_pointer<32>(&p)); | |
| if (section_size > size) | |
| section_size = size; | |
| size -= section_size; | |
| const char* section_name = reinterpret_cast<const char*>(p); | |
| section_size_type section_name_size = strlen(section_name) + 1; | |
| section_size -= section_name_size + 4; | |
| int vendor; | |
| const char* std_section = parameters->target().attributes_vendor(); | |
| if (std_section != NULL && strcmp(section_name, std_section) == 0) | |
| vendor = Object_attribute::OBJ_ATTR_PROC; | |
| else if (strcmp(section_name, "gnu") == 0) | |
| vendor = Object_attribute::OBJ_ATTR_GNU; | |
| else | |
| { | |
| // Other vendor section. Ignore it. | |
| p += section_name_size + section_size; | |
| continue; | |
| } | |
| p += section_name_size; | |
| while (section_size > 0) | |
| { | |
| const unsigned char* subsection_start = p; | |
| // Read vendor subsection index and size. | |
| size_t uleb128_len; | |
| uint64_t val = read_unsigned_LEB_128(p, &uleb128_len); | |
| p += uleb128_len; | |
| int tag = convert_types<int, uint64_t>(val); | |
| section_size_type subsection_size = | |
| convert_to_section_size_type(read_from_pointer<32>(&p)); | |
| section_size -= subsection_size; | |
| subsection_size -= (p - subsection_start); | |
| const unsigned char* end = p + subsection_size; | |
| switch (tag) | |
| { | |
| case Object_attribute::Tag_File: | |
| while (p < end) | |
| { | |
| val = read_unsigned_LEB_128(p, &uleb128_len); | |
| p += uleb128_len; | |
| tag = convert_types<int, uint64_t>(val); | |
| Vendor_object_attributes* pvoa = | |
| this->vendor_object_attributes_[vendor]; | |
| Object_attribute* attr = pvoa->new_attribute(tag); | |
| const char* string_arg; | |
| unsigned int int_arg; | |
| int type = Object_attribute::arg_type(vendor, tag); | |
| switch (type | |
| & (Object_attribute::ATTR_TYPE_FLAG_INT_VAL | |
| | Object_attribute::ATTR_TYPE_FLAG_STR_VAL)) | |
| { | |
| case (Object_attribute::ATTR_TYPE_FLAG_INT_VAL | |
| | Object_attribute::ATTR_TYPE_FLAG_STR_VAL): | |
| val = read_unsigned_LEB_128(p, &uleb128_len); | |
| p += uleb128_len; | |
| int_arg = convert_types<unsigned int, uint64_t>(val); | |
| string_arg = reinterpret_cast<const char *>(p); | |
| attr->set_int_value(int_arg); | |
| p += strlen(string_arg) + 1; | |
| break; | |
| case Object_attribute::ATTR_TYPE_FLAG_STR_VAL: | |
| string_arg = reinterpret_cast<const char *>(p); | |
| attr->set_string_value(string_arg); | |
| p += strlen(string_arg) + 1; | |
| break; | |
| case Object_attribute::ATTR_TYPE_FLAG_INT_VAL: | |
| val = read_unsigned_LEB_128(p, &uleb128_len); | |
| p += uleb128_len; | |
| int_arg = convert_types<unsigned int, uint64_t>(val); | |
| attr->set_int_value(int_arg); | |
| break; | |
| default: | |
| gold_unreachable(); | |
| } | |
| } | |
| break; | |
| case Object_attribute::Tag_Section: | |
| case Object_attribute::Tag_Symbol: | |
| // Don't have anywhere convenient to attach these. | |
| // Fall through for now. | |
| default: | |
| // Ignore things we don't know about. | |
| p += subsection_size; | |
| subsection_size = 0; | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| // Merge target-independent attributes from another Attribute_section_data | |
| // ASD from an object called NAME into this. | |
| void | |
| Attributes_section_data::merge( | |
| const char* name, | |
| const Attributes_section_data* pasd) | |
| { | |
| // The only common attribute is currently Tag_compatibility, | |
| // accepted in both processor and "gnu" sections. | |
| for (int vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; ++vendor) | |
| { | |
| // Handle Tag_compatibility. The tags are only compatible if the flags | |
| // are identical and, if the flags are '1', the strings are identical. | |
| // If the flags are non-zero, then we can only use the string "gnu". | |
| const Object_attribute* in_attr = | |
| &pasd->known_attributes(vendor)[Object_attribute::Tag_compatibility]; | |
| Object_attribute* out_attr = | |
| &this->known_attributes(vendor)[Object_attribute::Tag_compatibility]; | |
| if (in_attr->int_value() > 0 | |
| && in_attr->string_value() != "gnu") | |
| { | |
| gold_error(_("%s: must be processed by '%s' toolchain"), | |
| name, in_attr->string_value().c_str()); | |
| return; | |
| } | |
| if (in_attr->int_value() != out_attr->int_value() | |
| || in_attr->string_value() != out_attr->string_value()) | |
| { | |
| gold_error(_("%s: object tag '%d, %s' is " | |
| "incompatible with tag '%d, %s'"), | |
| name, in_attr->int_value(), | |
| in_attr->string_value().c_str(), | |
| out_attr->int_value(), | |
| out_attr->string_value().c_str()); | |
| } | |
| } | |
| } | |
| // Write to a buffer. | |
| void | |
| Attributes_section_data::write(std::vector<unsigned char>* buffer) const | |
| { | |
| buffer->push_back('A'); | |
| for (int vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; ++vendor) | |
| if (this->vendor_object_attributes_[vendor]->size() != 0) | |
| this->vendor_object_attributes_[vendor]->write(buffer); | |
| } | |
| // Methods for Output_attributes_section_data. | |
| // Write attributes section data to file OF. | |
| void | |
| Output_attributes_section_data::do_write(Output_file* of) | |
| { | |
| off_t offset = this->offset(); | |
| const section_size_type oview_size = | |
| convert_to_section_size_type(this->data_size()); | |
| unsigned char* const oview = of->get_output_view(offset, oview_size); | |
| std::vector<unsigned char> buffer; | |
| this->attributes_section_data_.write(&buffer); | |
| gold_assert(convert_to_section_size_type(buffer.size()) == oview_size); | |
| memcpy(oview, &buffer.front(), buffer.size()); | |
| of->write_output_view(this->offset(), oview_size, oview); | |
| } | |
| } // End namespace gold. |