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