OLD | NEW |
1 //===- subzero/src/IceELFSection.h - Model of ELF sections ------*- C++ -*-===// | 1 //===- subzero/src/IceELFSection.h - Model of ELF sections ------*- C++ -*-===// |
2 // | 2 // |
3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
4 // | 4 // |
5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
7 // | 7 // |
8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
9 /// | 9 /// |
10 /// \file | 10 /// \file |
(...skipping 18 matching lines...) Expand all Loading... |
29 | 29 |
30 /// Base representation of an ELF section. | 30 /// Base representation of an ELF section. |
31 class ELFSection { | 31 class ELFSection { |
32 ELFSection() = delete; | 32 ELFSection() = delete; |
33 ELFSection(const ELFSection &) = delete; | 33 ELFSection(const ELFSection &) = delete; |
34 ELFSection &operator=(const ELFSection &) = delete; | 34 ELFSection &operator=(const ELFSection &) = delete; |
35 | 35 |
36 public: | 36 public: |
37 virtual ~ELFSection() = default; | 37 virtual ~ELFSection() = default; |
38 | 38 |
39 /// Sentinel value for a section number/index for before the final | 39 /// Sentinel value for a section number/index for before the final section |
40 /// section index is actually known. The dummy NULL section will be assigned | 40 /// index is actually known. The dummy NULL section will be assigned number 0, |
41 /// number 0, and it is referenced by the dummy 0-th symbol in the symbol | 41 /// and it is referenced by the dummy 0-th symbol in the symbol table, so use |
42 /// table, so use max() instead of 0. | 42 /// max() instead of 0. |
43 enum { NoSectionNumber = std::numeric_limits<SizeT>::max() }; | 43 enum { NoSectionNumber = std::numeric_limits<SizeT>::max() }; |
44 | 44 |
45 /// Constructs an ELF section, filling in fields that will be known | 45 /// Constructs an ELF section, filling in fields that will be known once the |
46 /// once the *type* of section is decided. Other fields may be updated | 46 /// *type* of section is decided. Other fields may be updated incrementally or |
47 /// incrementally or only after the program is completely defined. | 47 /// only after the program is completely defined. |
48 ELFSection(const IceString &Name, Elf64_Word ShType, Elf64_Xword ShFlags, | 48 ELFSection(const IceString &Name, Elf64_Word ShType, Elf64_Xword ShFlags, |
49 Elf64_Xword ShAddralign, Elf64_Xword ShEntsize) | 49 Elf64_Xword ShAddralign, Elf64_Xword ShEntsize) |
50 : Name(Name), Header() { | 50 : Name(Name), Header() { |
51 Header.sh_type = ShType; | 51 Header.sh_type = ShType; |
52 Header.sh_flags = ShFlags; | 52 Header.sh_flags = ShFlags; |
53 Header.sh_addralign = ShAddralign; | 53 Header.sh_addralign = ShAddralign; |
54 Header.sh_entsize = ShEntsize; | 54 Header.sh_entsize = ShEntsize; |
55 } | 55 } |
56 | 56 |
57 /// Set the section number/index after it is finally known. | 57 /// Set the section number/index after it is finally known. |
(...skipping 19 matching lines...) Expand all Loading... |
77 void setInfoNum(Elf64_Word sh_info) { Header.sh_info = sh_info; } | 77 void setInfoNum(Elf64_Word sh_info) { Header.sh_info = sh_info; } |
78 | 78 |
79 void setFileOffset(Elf64_Off sh_offset) { Header.sh_offset = sh_offset; } | 79 void setFileOffset(Elf64_Off sh_offset) { Header.sh_offset = sh_offset; } |
80 | 80 |
81 Elf64_Xword getSectionAlign() const { return Header.sh_addralign; } | 81 Elf64_Xword getSectionAlign() const { return Header.sh_addralign; } |
82 | 82 |
83 /// Write the section header out with the given streamer. | 83 /// Write the section header out with the given streamer. |
84 template <bool IsELF64> void writeHeader(ELFStreamer &Str); | 84 template <bool IsELF64> void writeHeader(ELFStreamer &Str); |
85 | 85 |
86 protected: | 86 protected: |
87 /// Name of the section in convenient string form (instead of a index | 87 /// Name of the section in convenient string form (instead of a index into the |
88 /// into the Section Header String Table, which is not known till later). | 88 /// Section Header String Table, which is not known till later). |
89 const IceString Name; | 89 const IceString Name; |
90 | 90 |
91 // The fields of the header. May only be partially initialized, but should | 91 // The fields of the header. May only be partially initialized, but should |
92 // be fully initialized before writing. | 92 // be fully initialized before writing. |
93 Elf64_Shdr Header; | 93 Elf64_Shdr Header; |
94 | 94 |
95 /// The number of the section after laying out sections. | 95 /// The number of the section after laying out sections. |
96 SizeT Number = NoSectionNumber; | 96 SizeT Number = NoSectionNumber; |
97 }; | 97 }; |
98 | 98 |
99 /// Models text/code sections. Code is written out incrementally and the | 99 /// Models text/code sections. Code is written out incrementally and the size of |
100 /// size of the section is then updated incrementally. | 100 /// the section is then updated incrementally. |
101 class ELFTextSection : public ELFSection { | 101 class ELFTextSection : public ELFSection { |
102 ELFTextSection() = delete; | 102 ELFTextSection() = delete; |
103 ELFTextSection(const ELFTextSection &) = delete; | 103 ELFTextSection(const ELFTextSection &) = delete; |
104 ELFTextSection &operator=(const ELFTextSection &) = delete; | 104 ELFTextSection &operator=(const ELFTextSection &) = delete; |
105 | 105 |
106 public: | 106 public: |
107 using ELFSection::ELFSection; | 107 using ELFSection::ELFSection; |
108 | 108 |
109 void appendData(ELFStreamer &Str, const llvm::StringRef MoreData); | 109 void appendData(ELFStreamer &Str, const llvm::StringRef MoreData); |
110 }; | 110 }; |
111 | 111 |
112 /// Models data/rodata sections. Data is written out incrementally and the | 112 /// Models data/rodata sections. Data is written out incrementally and the size |
113 /// size of the section is then updated incrementally. | 113 /// of the section is then updated incrementally. Some rodata sections may have |
114 /// Some rodata sections may have fixed entsize and duplicates may be mergeable. | 114 /// fixed entsize and duplicates may be mergeable. |
115 class ELFDataSection : public ELFSection { | 115 class ELFDataSection : public ELFSection { |
116 ELFDataSection() = delete; | 116 ELFDataSection() = delete; |
117 ELFDataSection(const ELFDataSection &) = delete; | 117 ELFDataSection(const ELFDataSection &) = delete; |
118 ELFDataSection &operator=(const ELFDataSection &) = delete; | 118 ELFDataSection &operator=(const ELFDataSection &) = delete; |
119 | 119 |
120 public: | 120 public: |
121 using ELFSection::ELFSection; | 121 using ELFSection::ELFSection; |
122 | 122 |
123 void appendData(ELFStreamer &Str, const llvm::StringRef MoreData); | 123 void appendData(ELFStreamer &Str, const llvm::StringRef MoreData); |
124 | 124 |
125 void appendZeros(ELFStreamer &Str, SizeT NumBytes); | 125 void appendZeros(ELFStreamer &Str, SizeT NumBytes); |
126 | 126 |
127 void appendRelocationOffset(ELFStreamer &Str, bool IsRela, | 127 void appendRelocationOffset(ELFStreamer &Str, bool IsRela, |
128 RelocOffsetT RelocOffset); | 128 RelocOffsetT RelocOffset); |
129 | 129 |
130 /// Pad the next section offset for writing data elements to the requested | 130 /// Pad the next section offset for writing data elements to the requested |
131 /// alignment. If the section is NOBITS then do not actually write out | 131 /// alignment. If the section is NOBITS then do not actually write out the |
132 /// the padding and only update the section size. | 132 /// padding and only update the section size. |
133 void padToAlignment(ELFStreamer &Str, Elf64_Xword Align); | 133 void padToAlignment(ELFStreamer &Str, Elf64_Xword Align); |
134 }; | 134 }; |
135 | 135 |
136 /// Model of ELF symbol table entries. Besides keeping track of the fields | 136 /// Model of ELF symbol table entries. Besides keeping track of the fields |
137 /// required for an elf symbol table entry it also tracks the number that | 137 /// required for an elf symbol table entry it also tracks the number that |
138 /// represents the symbol's final index in the symbol table. | 138 /// represents the symbol's final index in the symbol table. |
139 struct ELFSym { | 139 struct ELFSym { |
140 Elf64_Sym Sym; | 140 Elf64_Sym Sym; |
141 ELFSection *Section; | 141 ELFSection *Section; |
142 SizeT Number; | 142 SizeT Number; |
143 | 143 |
144 /// Sentinel value for symbols that haven't been assigned a number yet. | 144 /// Sentinel value for symbols that haven't been assigned a number yet. The |
145 /// The dummy 0-th symbol will be assigned number 0, so don't use that. | 145 /// dummy 0-th symbol will be assigned number 0, so don't use that. |
146 enum { UnknownNumber = std::numeric_limits<SizeT>::max() }; | 146 enum { UnknownNumber = std::numeric_limits<SizeT>::max() }; |
147 | 147 |
148 void setNumber(SizeT N) { | 148 void setNumber(SizeT N) { |
149 assert(Number == UnknownNumber); | 149 assert(Number == UnknownNumber); |
150 Number = N; | 150 Number = N; |
151 } | 151 } |
152 | 152 |
153 SizeT getNumber() const { | 153 SizeT getNumber() const { |
154 assert(Number != UnknownNumber); | 154 assert(Number != UnknownNumber); |
155 return Number; | 155 return Number; |
156 } | 156 } |
157 }; | 157 }; |
158 | 158 |
159 /// Models a symbol table. Symbols may be added up until updateIndices is | 159 /// Models a symbol table. Symbols may be added up until updateIndices is |
160 /// called. At that point the indices of each symbol will be finalized. | 160 /// called. At that point the indices of each symbol will be finalized. |
161 class ELFSymbolTableSection : public ELFSection { | 161 class ELFSymbolTableSection : public ELFSection { |
162 ELFSymbolTableSection() = delete; | 162 ELFSymbolTableSection() = delete; |
163 ELFSymbolTableSection(const ELFSymbolTableSection &) = delete; | 163 ELFSymbolTableSection(const ELFSymbolTableSection &) = delete; |
164 ELFSymbolTableSection &operator=(const ELFSymbolTableSection &) = delete; | 164 ELFSymbolTableSection &operator=(const ELFSymbolTableSection &) = delete; |
165 | 165 |
166 public: | 166 public: |
167 ELFSymbolTableSection(const IceString &Name, Elf64_Word ShType, | 167 ELFSymbolTableSection(const IceString &Name, Elf64_Word ShType, |
168 Elf64_Xword ShFlags, Elf64_Xword ShAddralign, | 168 Elf64_Xword ShFlags, Elf64_Xword ShAddralign, |
169 Elf64_Xword ShEntsize) | 169 Elf64_Xword ShEntsize) |
170 : ELFSection(Name, ShType, ShFlags, ShAddralign, ShEntsize), | 170 : ELFSection(Name, ShType, ShFlags, ShAddralign, ShEntsize), |
171 NullSymbol(nullptr) {} | 171 NullSymbol(nullptr) {} |
172 | 172 |
173 /// Create initial entry for a symbol when it is defined. | 173 /// Create initial entry for a symbol when it is defined. Each entry should |
174 /// Each entry should only be defined once. | 174 /// only be defined once. We might want to allow Name to be a dummy name |
175 /// We might want to allow Name to be a dummy name initially, then | 175 /// initially, then get updated to the real thing, since Data initializers are |
176 /// get updated to the real thing, since Data initializers are read | 176 /// read before the bitcode's symbol table is read. |
177 /// before the bitcode's symbol table is read. | |
178 void createDefinedSym(const IceString &Name, uint8_t Type, uint8_t Binding, | 177 void createDefinedSym(const IceString &Name, uint8_t Type, uint8_t Binding, |
179 ELFSection *Section, RelocOffsetT Offset, SizeT Size); | 178 ELFSection *Section, RelocOffsetT Offset, SizeT Size); |
180 | 179 |
181 /// Note that a symbol table entry needs to be created for the given | 180 /// Note that a symbol table entry needs to be created for the given symbol |
182 /// symbol because it is undefined. | 181 /// because it is undefined. |
183 void noteUndefinedSym(const IceString &Name, ELFSection *NullSection); | 182 void noteUndefinedSym(const IceString &Name, ELFSection *NullSection); |
184 | 183 |
185 const ELFSym *findSymbol(const IceString &Name) const; | 184 const ELFSym *findSymbol(const IceString &Name) const; |
186 | 185 |
187 void createNullSymbol(ELFSection *NullSection); | 186 void createNullSymbol(ELFSection *NullSection); |
188 const ELFSym *getNullSymbol() const { return NullSymbol; } | 187 const ELFSym *getNullSymbol() const { return NullSymbol; } |
189 | 188 |
190 size_t getSectionDataSize() const { | 189 size_t getSectionDataSize() const { |
191 return (LocalSymbols.size() + GlobalSymbols.size()) * Header.sh_entsize; | 190 return (LocalSymbols.size() + GlobalSymbols.size()) * Header.sh_entsize; |
192 } | 191 } |
193 | 192 |
194 size_t getNumLocals() const { return LocalSymbols.size(); } | 193 size_t getNumLocals() const { return LocalSymbols.size(); } |
195 | 194 |
196 void updateIndices(const ELFStringTableSection *StrTab); | 195 void updateIndices(const ELFStringTableSection *StrTab); |
197 | 196 |
198 void writeData(ELFStreamer &Str, bool IsELF64); | 197 void writeData(ELFStreamer &Str, bool IsELF64); |
199 | 198 |
200 private: | 199 private: |
201 // Map from symbol name to its symbol information. | 200 // Map from symbol name to its symbol information. This assumes symbols are |
202 // This assumes symbols are unique across all sections. | 201 // unique across all sections. |
203 using SymtabKey = IceString; | 202 using SymtabKey = IceString; |
204 using SymMap = std::map<SymtabKey, ELFSym>; | 203 using SymMap = std::map<SymtabKey, ELFSym>; |
205 | 204 |
206 template <bool IsELF64> | 205 template <bool IsELF64> |
207 void writeSymbolMap(ELFStreamer &Str, const SymMap &Map); | 206 void writeSymbolMap(ELFStreamer &Str, const SymMap &Map); |
208 | 207 |
209 const ELFSym *NullSymbol; | 208 const ELFSym *NullSymbol; |
210 // Keep Local and Global symbols separate, since the sh_info needs to | 209 // Keep Local and Global symbols separate, since the sh_info needs to know |
211 // know the index of the last LOCAL. | 210 // the index of the last LOCAL. |
212 SymMap LocalSymbols; | 211 SymMap LocalSymbols; |
213 SymMap GlobalSymbols; | 212 SymMap GlobalSymbols; |
214 }; | 213 }; |
215 | 214 |
216 /// Models a relocation section. | 215 /// Models a relocation section. |
217 class ELFRelocationSection : public ELFSection { | 216 class ELFRelocationSection : public ELFSection { |
218 ELFRelocationSection() = delete; | 217 ELFRelocationSection() = delete; |
219 ELFRelocationSection(const ELFRelocationSection &) = delete; | 218 ELFRelocationSection(const ELFRelocationSection &) = delete; |
220 ELFRelocationSection &operator=(const ELFRelocationSection &) = delete; | 219 ELFRelocationSection &operator=(const ELFRelocationSection &) = delete; |
221 | 220 |
222 public: | 221 public: |
223 ELFRelocationSection(const IceString &Name, Elf64_Word ShType, | 222 ELFRelocationSection(const IceString &Name, Elf64_Word ShType, |
224 Elf64_Xword ShFlags, Elf64_Xword ShAddralign, | 223 Elf64_Xword ShFlags, Elf64_Xword ShAddralign, |
225 Elf64_Xword ShEntsize) | 224 Elf64_Xword ShEntsize) |
226 : ELFSection(Name, ShType, ShFlags, ShAddralign, ShEntsize), | 225 : ELFSection(Name, ShType, ShFlags, ShAddralign, ShEntsize), |
227 RelatedSection(nullptr) {} | 226 RelatedSection(nullptr) {} |
228 | 227 |
229 const ELFSection *getRelatedSection() const { return RelatedSection; } | 228 const ELFSection *getRelatedSection() const { return RelatedSection; } |
230 void setRelatedSection(const ELFSection *Section) { | 229 void setRelatedSection(const ELFSection *Section) { |
231 RelatedSection = Section; | 230 RelatedSection = Section; |
232 } | 231 } |
233 | 232 |
234 /// Track additional relocations which start out relative to offset 0, | 233 /// Track additional relocations which start out relative to offset 0, but |
235 /// but should be adjusted to be relative to BaseOff. | 234 /// should be adjusted to be relative to BaseOff. |
236 void addRelocations(RelocOffsetT BaseOff, const FixupRefList &FixupRefs); | 235 void addRelocations(RelocOffsetT BaseOff, const FixupRefList &FixupRefs); |
237 | 236 |
238 /// Track a single additional relocation. | 237 /// Track a single additional relocation. |
239 void addRelocation(const AssemblerFixup &Fixup) { Fixups.push_back(Fixup); } | 238 void addRelocation(const AssemblerFixup &Fixup) { Fixups.push_back(Fixup); } |
240 | 239 |
241 size_t getSectionDataSize() const; | 240 size_t getSectionDataSize() const; |
242 | 241 |
243 template <bool IsELF64> | 242 template <bool IsELF64> |
244 void writeData(const GlobalContext &Ctx, ELFStreamer &Str, | 243 void writeData(const GlobalContext &Ctx, ELFStreamer &Str, |
245 const ELFSymbolTableSection *SymTab); | 244 const ELFSymbolTableSection *SymTab); |
246 | 245 |
247 bool isRela() const { return Header.sh_type == SHT_RELA; } | 246 bool isRela() const { return Header.sh_type == SHT_RELA; } |
248 | 247 |
249 private: | 248 private: |
250 const ELFSection *RelatedSection; | 249 const ELFSection *RelatedSection; |
251 FixupList Fixups; | 250 FixupList Fixups; |
252 }; | 251 }; |
253 | 252 |
254 /// Models a string table. The user will build the string table by | 253 /// Models a string table. The user will build the string table by adding |
255 /// adding strings incrementally. At some point, all strings should be | 254 /// strings incrementally. At some point, all strings should be known and |
256 /// known and doLayout() should be called. After that, no other | 255 /// doLayout() should be called. After that, no other strings may be added. |
257 /// strings may be added. However, the final offsets of the strings | 256 /// However, the final offsets of the strings can be discovered and used to fill |
258 /// can be discovered and used to fill out section headers and symbol | 257 /// out section headers and symbol table entries. |
259 /// table entries. | |
260 class ELFStringTableSection : public ELFSection { | 258 class ELFStringTableSection : public ELFSection { |
261 ELFStringTableSection() = delete; | 259 ELFStringTableSection() = delete; |
262 ELFStringTableSection(const ELFStringTableSection &) = delete; | 260 ELFStringTableSection(const ELFStringTableSection &) = delete; |
263 ELFStringTableSection &operator=(const ELFStringTableSection &) = delete; | 261 ELFStringTableSection &operator=(const ELFStringTableSection &) = delete; |
264 | 262 |
265 public: | 263 public: |
266 using ELFSection::ELFSection; | 264 using ELFSection::ELFSection; |
267 | 265 |
268 /// Add a string to the table, in preparation for final layout. | 266 /// Add a string to the table, in preparation for final layout. |
269 void add(const IceString &Str); | 267 void add(const IceString &Str); |
270 | 268 |
271 /// Finalizes the layout of the string table and fills in the section Data. | 269 /// Finalizes the layout of the string table and fills in the section Data. |
272 void doLayout(); | 270 void doLayout(); |
273 | 271 |
274 /// The first byte of the string table should be \0, so it is an | 272 /// The first byte of the string table should be \0, so it is an invalid |
275 /// invalid index. Indices start out as unknown until layout is complete. | 273 /// index. Indices start out as unknown until layout is complete. |
276 enum { UnknownIndex = 0 }; | 274 enum { UnknownIndex = 0 }; |
277 | 275 |
278 /// Grabs the final index of a string after layout. Returns UnknownIndex | 276 /// Grabs the final index of a string after layout. Returns UnknownIndex if |
279 /// if the string's index is not found. | 277 /// the string's index is not found. |
280 size_t getIndex(const IceString &Str) const; | 278 size_t getIndex(const IceString &Str) const; |
281 | 279 |
282 llvm::StringRef getSectionData() const { | 280 llvm::StringRef getSectionData() const { |
283 assert(isLaidOut()); | 281 assert(isLaidOut()); |
284 return llvm::StringRef(reinterpret_cast<const char *>(StringData.data()), | 282 return llvm::StringRef(reinterpret_cast<const char *>(StringData.data()), |
285 StringData.size()); | 283 StringData.size()); |
286 } | 284 } |
287 | 285 |
288 size_t getSectionDataSize() const { return getSectionData().size(); } | 286 size_t getSectionDataSize() const { return getSectionData().size(); } |
289 | 287 |
290 private: | 288 private: |
291 bool isLaidOut() const { return !StringData.empty(); } | 289 bool isLaidOut() const { return !StringData.empty(); } |
292 | 290 |
293 /// Strings can share a string table entry if they share the same | 291 /// Strings can share a string table entry if they share the same suffix. |
294 /// suffix. E.g., "pop" and "lollipop" can both use the characters | 292 /// E.g., "pop" and "lollipop" can both use the characters in "lollipop", but |
295 /// in "lollipop", but "pops" cannot, and "unpop" cannot either. | 293 /// "pops" cannot, and "unpop" cannot either. Though, "pop", "lollipop", and |
296 /// Though, "pop", "lollipop", and "unpop" share "pop" as the suffix, | 294 /// "unpop" share "pop" as the suffix, "pop" can only share the characters |
297 /// "pop" can only share the characters with one of them. | 295 /// with one of them. |
298 struct SuffixComparator { | 296 struct SuffixComparator { |
299 bool operator()(const IceString &StrA, const IceString &StrB) const; | 297 bool operator()(const IceString &StrA, const IceString &StrB) const; |
300 }; | 298 }; |
301 | 299 |
302 using StringToIndexType = std::map<IceString, size_t, SuffixComparator>; | 300 using StringToIndexType = std::map<IceString, size_t, SuffixComparator>; |
303 | 301 |
304 /// Track strings to their index. Index will be UnknownIndex if not | 302 /// Track strings to their index. Index will be UnknownIndex if not yet laid |
305 /// yet laid out. | 303 /// out. |
306 StringToIndexType StringToIndexMap; | 304 StringToIndexType StringToIndexMap; |
307 | 305 |
308 using RawDataType = std::vector<uint8_t>; | 306 using RawDataType = std::vector<uint8_t>; |
309 RawDataType StringData; | 307 RawDataType StringData; |
310 }; | 308 }; |
311 | 309 |
312 template <bool IsELF64> void ELFSection::writeHeader(ELFStreamer &Str) { | 310 template <bool IsELF64> void ELFSection::writeHeader(ELFStreamer &Str) { |
313 Str.writeELFWord<IsELF64>(Header.sh_name); | 311 Str.writeELFWord<IsELF64>(Header.sh_name); |
314 Str.writeELFWord<IsELF64>(Header.sh_type); | 312 Str.writeELFWord<IsELF64>(Header.sh_type); |
315 Str.writeELFXword<IsELF64>(Header.sh_flags); | 313 Str.writeELFXword<IsELF64>(Header.sh_flags); |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
376 Rel.setSymbolAndType(Symbol->getNumber(), Fixup.kind()); | 374 Rel.setSymbolAndType(Symbol->getNumber(), Fixup.kind()); |
377 Str.writeAddrOrOffset<IsELF64>(Rel.r_offset); | 375 Str.writeAddrOrOffset<IsELF64>(Rel.r_offset); |
378 Str.writeELFWord<IsELF64>(Rel.r_info); | 376 Str.writeELFWord<IsELF64>(Rel.r_info); |
379 } | 377 } |
380 } | 378 } |
381 } | 379 } |
382 | 380 |
383 } // end of namespace Ice | 381 } // end of namespace Ice |
384 | 382 |
385 #endif // SUBZERO_SRC_ICEELFSECTION_H | 383 #endif // SUBZERO_SRC_ICEELFSECTION_H |
OLD | NEW |