• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- ELFAttribute.cpp ---------------------------------------------------===//
2 //
3 //                     The MCLinker Project
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 #include <mcld/Target/ELFAttribute.h>
10 
11 #include <mcld/ADT/SizeTraits.h>
12 #include <mcld/Fragment/RegionFragment.h>
13 #include <mcld/LD/LDSection.h>
14 #include <mcld/LD/SectionData.h>
15 #include <mcld/LinkerConfig.h>
16 #include <mcld/MC/Input.h>
17 #include <mcld/Support/LEB128.h>
18 #include <mcld/Support/MemoryArea.h>
19 #include <mcld/Support/MsgHandling.h>
20 #include <mcld/Target/ELFAttributeValue.h>
21 #include <mcld/Target/GNULDBackend.h>
22 
23 #include <llvm/ADT/STLExtras.h>
24 #include <llvm/Support/Host.h>
25 
26 #include <cstring>
27 
28 using namespace mcld;
29 
30 //===----------------------------------------------------------------------===//
31 // ELFAttribute
32 //===----------------------------------------------------------------------===//
~ELFAttribute()33 ELFAttribute::~ELFAttribute()
34 {
35   llvm::DeleteContainerPointers(m_Subsections);
36   return;
37 }
38 
merge(const Input & pInput,LDSection & pInputAttrSectHdr)39 bool ELFAttribute::merge(const Input &pInput, LDSection &pInputAttrSectHdr)
40 {
41   // Skip corrupt subsection
42   if (pInputAttrSectHdr.size() < MinimalELFAttributeSectionSize)
43     return true;
44 
45   // Obtain the region containing the attribute data. Expect exactly one
46   // RegionFragment in the section data.
47   const SectionData* sect_data = pInputAttrSectHdr.getSectionData();
48 
49   // FIXME: Why is 2?
50   if ((sect_data->size() != 2) ||
51       (!llvm::isa<RegionFragment>(sect_data->front()))) {
52     return true;
53   }
54 
55   const RegionFragment& region_frag =
56       llvm::cast<RegionFragment>(sect_data->front());
57 
58   llvm::StringRef region = region_frag.getRegion();
59 
60   // Parse the ELF attribute section header. ARM [ABI-addenda], 2.2.3.
61   //
62   // <format-version: ‘A’>
63   // [ <uint32: subsection-length> NTBS: vendor-name
64   //   <bytes: vendor-data>
65   // ]*
66   const char *attribute_data = region.begin();
67 
68   // format-version
69   if (attribute_data[0] != FormatVersion) {
70     warning(diag::warn_unsupported_attribute_section_format)
71         << pInput.name() << attribute_data[0];
72     return true;
73   }
74 
75   size_t subsection_offset = FormatVersionFieldSize;
76 
77   // Iterate all subsections containing in this attribute section.
78   do {
79     const char *subsection_data = region.begin() + subsection_offset;
80 
81     // subsection-length
82     uint32_t subsection_length =
83         *reinterpret_cast<const uint32_t*>(subsection_data);
84 
85     if(llvm::sys::IsLittleEndianHost != m_Config.targets().isLittleEndian())
86       bswap32(subsection_length);
87 
88     // vendor-name
89     const char* vendor_name = subsection_data + SubsectionLengthFieldSize;
90     const size_t vendor_name_length = ::strlen(vendor_name) + 1 /* '\0' */;
91 
92     // Check the length.
93     if ((vendor_name_length <= 1) ||
94         (subsection_length <= (SubsectionLengthFieldSize + vendor_name_length)))
95       return true;
96 
97     // Select the attribute subsection.
98     Subsection *subsection = getSubsection(vendor_name);
99 
100     // Only process the subsections whose vendor can be recognized.
101     if (subsection == NULL) {
102       warning(diag::warn_unrecognized_vendor_subsection)
103           << vendor_name << pInput.name();
104     } else {
105       // vendor-data
106       size_t vendor_data_offset = subsection_offset +
107                                   SubsectionLengthFieldSize +
108                                   vendor_name_length;
109       size_t vendor_data_size = subsection_length - SubsectionLengthFieldSize -
110                                 vendor_name_length;
111 
112       ConstAddress vendor_data =
113           reinterpret_cast<ConstAddress>(region.begin()) + vendor_data_offset;
114 
115       // Merge the vendor data in the subsection.
116       if (!subsection->merge(pInput, vendor_data, vendor_data_size))
117         return false;
118     }
119 
120     subsection_offset += subsection_length;
121   } while ((subsection_offset + SubsectionLengthFieldSize) < pInputAttrSectHdr.size());
122 
123   return true;
124 }
125 
sizeOutput() const126 size_t ELFAttribute::sizeOutput() const
127 {
128   size_t total_size = FormatVersionFieldSize;
129 
130   for (llvm::SmallVectorImpl<Subsection*>::const_iterator
131           subsec_it = m_Subsections.begin(), subsec_end = m_Subsections.end();
132        subsec_it != subsec_end; ++subsec_it) {
133     total_size += (*subsec_it)->sizeOutput();
134   }
135   return total_size;
136 }
137 
emit(MemoryRegion & pRegion) const138 size_t ELFAttribute::emit(MemoryRegion &pRegion) const
139 {
140   // ARM [ABI-addenda], 2.2.3
141   uint64_t total_size = 0;
142 
143   // Write format-version.
144   char* buffer = reinterpret_cast<char*>(pRegion.begin());
145   buffer[0] = FormatVersion;
146   total_size += FormatVersionFieldSize;
147 
148   for (llvm::SmallVectorImpl<Subsection*>::const_iterator
149           subsec_it = m_Subsections.begin(), subsec_end = m_Subsections.end();
150        subsec_it != subsec_end; ++subsec_it) {
151     // Write out subsection.
152     total_size += (*subsec_it)->emit(buffer + total_size);
153   }
154 
155   return total_size;
156 }
157 
registerAttributeData(ELFAttributeData & pAttrData)158 void ELFAttribute::registerAttributeData(ELFAttributeData& pAttrData)
159 {
160   assert((getSubsection(pAttrData.getVendorName()) == NULL) &&
161          "Multiple attribute data for a vendor!");
162   m_Subsections.push_back(new Subsection(*this, pAttrData));
163   return;
164 }
165 
166 ELFAttribute::Subsection *
getSubsection(llvm::StringRef pVendorName) const167 ELFAttribute::getSubsection(llvm::StringRef pVendorName) const
168 {
169   // Search m_Subsections linearly.
170   for (llvm::SmallVectorImpl<Subsection*>::const_iterator
171           subsec_it = m_Subsections.begin(), subsec_end = m_Subsections.end();
172        subsec_it != subsec_end; ++subsec_it) {
173     Subsection* const subsection = *subsec_it;
174     if (subsection->isMyAttribute(pVendorName)) {
175       return subsection;
176     }
177   }
178 
179   // Not found
180   return NULL;
181 }
182 
183 //===----------------------------------------------------------------------===//
184 // ELFAttribute::Subsection
185 //===----------------------------------------------------------------------===//
merge(const Input & pInput,ConstAddress pData,size_t pSize)186 bool ELFAttribute::Subsection::merge(const Input &pInput,
187                                      ConstAddress pData,
188                                      size_t pSize)
189 {
190   const bool need_swap = (llvm::sys::IsLittleEndianHost !=
191                               m_Parent.config().targets().isLittleEndian());
192   // Read attribute sub-subsection from vendor data.
193   //
194   // ARM [ABI-addenda], 2.2.4:
195   //
196   // [   Tag_File    (=1) <uint32: byte-size> <attribute>*
197   //   | Tag_Section (=2) <uint32: byte-size> <section number>* 0 <attribute>*
198   //   | Tag_symbol  (=3) <unit32: byte-size> <symbol number>* 0 <attribute>*
199   // ] +
200   const char *subsubsection_data = reinterpret_cast<const char*>(pData);
201   size_t remaining_size = pSize;
202 
203   if (!m_AttrData.preMerge(pInput)) {
204     return false;
205   }
206 
207   while (remaining_size > ELFAttribute::MinimalELFAttributeSubsectionSize) {
208     // The tag of sub-subsection is encoded in ULEB128.
209     size_t tag_size;
210     uint64_t tag = leb128::decode<uint64_t>(subsubsection_data, tag_size);
211 
212     if ((tag_size + 4 /* byte-size */) >= remaining_size)
213       break;
214 
215     size_t subsubsection_length =
216         *reinterpret_cast<const uint32_t*>(subsubsection_data + tag_size);
217 
218     if (need_swap)
219       bswap32(subsubsection_length);
220 
221     if (subsubsection_length > remaining_size) {
222       // The subsubsection is corrupted. Try our best to process it.
223       subsubsection_length = remaining_size;
224     }
225 
226     switch (tag) {
227       case ELFAttributeData::Tag_File: {
228         ELFAttributeData::TagType tag;
229         ELFAttributeValue in_attr;
230         // The offset from the start of sub-subsection that <attribute> located
231         size_t attribute_offset = tag_size + 4 /* byte-size */;
232 
233         const char* attr_buf = subsubsection_data + attribute_offset;
234         size_t attr_size = subsubsection_length - attribute_offset;
235 
236         // Read attributes from the stream.
237         do {
238           if (!ELFAttributeData::ReadTag(tag, attr_buf, attr_size))
239             break;
240 
241           ELFAttributeValue *out_attr;
242           bool is_newly_created;
243 
244           std::tie(out_attr, is_newly_created) =
245               m_AttrData.getOrCreateAttributeValue(tag);
246 
247           assert(out_attr != NULL);
248 
249           if (is_newly_created) {
250             // Directly read the attribute value to the out_attr.
251             if (!ELFAttributeData::ReadValue(*out_attr, attr_buf, attr_size))
252               break;
253           } else {
254             // The attribute has been defined previously. Read the attribute
255             // to a temporary storage in_attr and perform the merge.
256             in_attr.reset();
257             in_attr.setType(out_attr->type());
258 
259             // Read the attribute value.
260             if (!ELFAttributeData::ReadValue(in_attr, attr_buf, attr_size))
261               break;
262 
263             // Merge if the read attribute value is different than current one
264             // in output.
265             if ((in_attr != *out_attr) &&
266                 !m_AttrData.merge(m_Parent.config(), pInput, tag, in_attr)) {
267               // Fail to merge the attribute.
268               return false;
269             }
270           }
271         } while (attr_size > 0);
272 
273         break;
274       }
275       // Skip sub-subsection tagged with Tag_Section and Tag_Symbol. They are
276       // deprecated since ARM [ABI-addenda] r2.09.
277       case ELFAttributeData::Tag_Section:
278       case ELFAttributeData::Tag_Symbol:
279       // Skip any unknown tags.
280       default: {
281         break;
282       }
283     }
284 
285     // Update subsubsection_data and remaining_size for next.
286     subsubsection_data += subsubsection_length;
287     remaining_size -= subsubsection_length;
288   } // while (remaining_size > ELFAttribute::MinimalELFAttributeSubsectionSize)
289 
290   return m_AttrData.postMerge(m_Parent.config(), pInput);
291 }
292 
sizeOutput() const293 size_t ELFAttribute::Subsection::sizeOutput() const
294 {
295   // ARM [ABI-addenda], 2.2.3 and 2.2.4
296   return ELFAttribute::SubsectionLengthFieldSize +
297             m_AttrData.getVendorName().length() /* vendor-name */ +
298             1 /* NULL-terminator for vendor-name */ +
299             1 /* Tag_File */ +
300             sizeof(uint32_t) /* length of sub-subsection */ +
301             m_AttrData.sizeOutput();
302 }
303 
emit(char * pBuf) const304 size_t ELFAttribute::Subsection::emit(char *pBuf) const
305 {
306   // ARM [ABI-addenda], 2.2.3 and 2.2.4
307   const bool need_swap = (llvm::sys::IsLittleEndianHost !=
308                               m_Parent.config().targets().isLittleEndian());
309 
310   char *buffer = pBuf;
311 
312   // The subsection-length and byte-size field in sub-subsection will be patched
313   // later after writing out all attribute data.
314   char *subsection_length_hole = NULL;
315   char *subsubsection_length_hole = NULL;
316 
317   // Reserve space for subsection-length.
318   subsection_length_hole = buffer;
319   buffer += 4;
320 
321   // Write vendor-name.
322   const std::string &vendor_name = m_AttrData.getVendorName();
323   ::memcpy(buffer, vendor_name.c_str(), vendor_name.length());
324   buffer += vendor_name.length();
325 
326   // Write NULL-terminator for vendor-name.
327   *buffer++ = '\0';
328 
329   // Write Tag_File (0x01).
330   *buffer++ = '\x01';
331 
332   // Reserve space for byte-size for sub-subsection.
333   subsubsection_length_hole = buffer;
334   buffer += sizeof(uint32_t);
335 
336   // Write attribute data.
337   uint32_t subsubsection_length = m_AttrData.emit(buffer);
338 
339   // Calculate value of subsection-length.
340   uint32_t subsection_length = (buffer - pBuf) + subsubsection_length;
341 
342   // ARM [ABI-addenda] 2.2.4
343   //
344   // The byte-size in sub-subsection includes Tag_File (1-byte) and the size
345   // field of itself (4-byte).
346   subsubsection_length += 1 /* Tag_File */ + 4 /* size of byte-size */;
347 
348   // Patch subsubsection_length_hole.
349   assert(subsubsection_length_hole != NULL);
350 
351   if(need_swap)
352     bswap32(subsubsection_length);
353 
354   ::memcpy(subsubsection_length_hole, &subsubsection_length, sizeof(uint32_t));
355 
356   // Write subsection-length in subsection_length_hole.
357   if(need_swap)
358     bswap32(subsection_length);
359 
360   assert(subsection_length_hole != NULL);
361   ::memcpy(subsection_length_hole, &subsection_length, sizeof(uint32_t));
362 
363   return subsection_length;
364 }
365