source: CLRX/CLRadeonExtender/trunk/amdbin/ElfBinaries.cpp @ 3738

Last change on this file since 3738 was 3738, checked in by matszpk, 3 years ago

CLRadeonExtender: ElfBin?: put to symtab and dynsym info index of the last local symbol (conform with standard).

File size: 53.0 KB
Line 
1/*
2 *  CLRadeonExtender - Unofficial OpenCL Radeon Extensions Library
3 *  Copyright (C) 2014-2018 Mateusz Szpakowski
4 *
5 *  This library is free software; you can redistribute it and/or
6 *  modify it under the terms of the GNU Lesser General Public
7 *  License as published by the Free Software Foundation; either
8 *  version 2.1 of the License, or (at your option) any later version.
9 *
10 *  This library is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 *  Lesser General Public License for more details.
14 *
15 *  You should have received a copy of the GNU Lesser General Public
16 *  License along with this library; if not, write to the Free Software
17 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19
20#include <CLRX/Config.h>
21#include <algorithm>
22#include <cstdlib>
23#include <cstring>
24#include <cstdint>
25#include <climits>
26#include <utility>
27#include <string>
28#include <cassert>
29#include <CLRX/amdbin/Elf.h>
30#include <CLRX/utils/Utilities.h>
31#include <CLRX/utils/MemAccess.h>
32#include <CLRX/amdbin/AmdBinaries.h>
33
34static const uint32_t elfMagicValue = 0x464c457fU;
35
36/* INFO: in this file is used ULEV function for conversion
37 * from LittleEndian and unaligned access to other memory access policy and endianness
38 * Please use this function whenever you want to get or set word in ELF binary,
39 * because ELF binaries can be unaligned in memory (as inner binaries).
40 */
41
42using namespace CLRX;
43
44// BinException costuctor
45BinException::BinException(const std::string& message) : Exception(message)
46{ }
47
48// BinGenException costuctor
49BinGenException::BinGenException(const std::string& message) : Exception(message)
50{ }
51
52/* determine unfinished strings region in string table for checking further consistency */
53static size_t unfinishedRegionOfStringTable(const cxbyte* table, size_t size)
54{
55    if (size == 0) // if zero
56        return 0;
57    size_t k;
58    for (k = size-1; k>0 && table[k]!=0; k--);
59   
60    return (table[k]==0)?k+1:k;
61}
62
63/* elf32 types */
64
65const cxbyte CLRX::Elf32Types::ELFCLASS = ELFCLASS32;
66const uint32_t CLRX::Elf32Types::bitness = 32;
67const char* CLRX::Elf32Types::bitName = "32";
68
69/* elf64 types */
70
71const cxbyte CLRX::Elf64Types::ELFCLASS = ELFCLASS64;
72const cxuint CLRX::Elf64Types::bitness = 64;
73const char* CLRX::Elf64Types::bitName = "64";
74
75/* ElfBinaryTemplate */
76
77template<typename Types>
78ElfBinaryTemplate<Types>::ElfBinaryTemplate() : binaryCodeSize(0), binaryCode(nullptr),
79        sectionStringTable(nullptr), symbolStringTable(nullptr),
80        symbolTable(nullptr), dynSymStringTable(nullptr), dynSymTable(nullptr),
81        noteTable(nullptr), symbolsNum(0), dynSymbolsNum(0),
82        noteTableSize(0), dynamicsNum(0), symbolEntSize(0), dynSymEntSize(0),
83        dynamicEntSize(0)
84{ }
85
86template<typename Types>
87ElfBinaryTemplate<Types>::~ElfBinaryTemplate()
88{ }
89
90template<typename Types>
91ElfBinaryTemplate<Types>::ElfBinaryTemplate(size_t _binaryCodeSize, cxbyte* _binaryCode,
92             Flags _creationFlags) : creationFlags(_creationFlags),
93        binaryCodeSize(_binaryCodeSize), binaryCode(_binaryCode),
94        sectionStringTable(nullptr), symbolStringTable(nullptr),
95        symbolTable(nullptr), dynSymStringTable(nullptr), dynSymTable(nullptr),
96        noteTable(nullptr), symbolsNum(0), dynSymbolsNum(0),
97        noteTableSize(0), dynamicsNum(0), symbolEntSize(0), dynSymEntSize(0),
98        dynamicEntSize(0)     
99{
100    if (binaryCodeSize < sizeof(typename Types::Ehdr))
101        throw BinException("Binary is too small!!!");
102   
103    const typename Types::Ehdr* ehdr =
104            reinterpret_cast<const typename Types::Ehdr*>(binaryCode);
105   
106    // checking ELF magic, ELFCLASS and endian (only little-endian accepted)
107    if (ULEV(*reinterpret_cast<const uint32_t*>(binaryCode)) != elfMagicValue)
108        throw BinException("This is not ELF binary");
109    if (ehdr->e_ident[EI_CLASS] != Types::ELFCLASS)
110        throw BinException(std::string("This is not ")+Types::bitName+"bit ELF binary");
111    if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB)
112        throw BinException("Other than little-endian binaries are not supported!");
113   
114    if ((ULEV(ehdr->e_phoff) == 0 && ULEV(ehdr->e_phnum) != 0))
115        throw BinException("Elf invalid phoff and phnum combination");
116    if (ULEV(ehdr->e_phoff) != 0)
117    {
118        /* reading and checking program headers */
119        if (ULEV(ehdr->e_phoff) > binaryCodeSize)
120            throw BinException("ProgramHeaders offset out of range!");
121        if (usumGt(ULEV(ehdr->e_phoff),
122                   ((typename Types::Word)ULEV(ehdr->e_phentsize))*ULEV(ehdr->e_phnum),
123                   binaryCodeSize))
124            throw BinException("ProgramHeaders offset+size out of range!");
125       
126        cxuint phnum = ULEV(ehdr->e_phnum);
127        // checking program header segment offset ranges
128        for (cxuint i = 0; i < phnum; i++)
129        {
130            const typename Types::Phdr& phdr = getProgramHeader(i);
131            if (ULEV(phdr.p_offset) > binaryCodeSize)
132                throw BinException("Segment offset out of range!");
133            if (usumGt(ULEV(phdr.p_offset), ULEV(phdr.p_filesz), binaryCodeSize))
134                throw BinException("Segment offset+size out of range!");
135        }
136    }
137   
138    if ((ULEV(ehdr->e_shoff) == 0 && ULEV(ehdr->e_shnum) != 0))
139        throw BinException("Elf invalid shoff and shnum combination");
140    if (ULEV(ehdr->e_shoff) != 0 && ULEV(ehdr->e_shstrndx) != SHN_UNDEF)
141    {
142        /* indexing of sections */
143        if (ULEV(ehdr->e_shoff) > binaryCodeSize)
144            throw BinException("SectionHeaders offset out of range!");
145        if (usumGt(ULEV(ehdr->e_shoff),
146                  ((typename Types::Word)ULEV(ehdr->e_shentsize))*ULEV(ehdr->e_shnum),
147                  binaryCodeSize))
148            throw BinException("SectionHeaders offset+size out of range!");
149        if (ULEV(ehdr->e_shstrndx) >= ULEV(ehdr->e_shnum))
150            throw BinException("Shstrndx out of range!");
151       
152        typename Types::Shdr& shstrShdr = getSectionHeader(ULEV(ehdr->e_shstrndx));
153        sectionStringTable = binaryCode + ULEV(shstrShdr.sh_offset);
154        const size_t unfinishedShstrPos = unfinishedRegionOfStringTable(
155                    sectionStringTable, ULEV(shstrShdr.sh_size));
156       
157        const typename Types::Shdr* symTableHdr = nullptr;
158        const typename Types::Shdr* dynSymTableHdr = nullptr;
159        const typename Types::Shdr* noteTableHdr = nullptr;
160        const typename Types::Shdr* dynamicTableHdr = nullptr;
161       
162        cxuint shnum = ULEV(ehdr->e_shnum);
163        if ((creationFlags & ELF_CREATE_SECTIONMAP) != 0)
164            sectionIndexMap.resize(shnum);
165        for (cxuint i = 0; i < shnum; i++)
166        {
167            const typename Types::Shdr& shdr = getSectionHeader(i);
168            /// checking section offset ranges
169            if (ULEV(shdr.sh_offset) > binaryCodeSize)
170                throw BinException("Section offset out of range!");
171            if (ULEV(shdr.sh_type) != SHT_NOBITS)
172                if (usumGt(ULEV(shdr.sh_offset), ULEV(shdr.sh_size), binaryCodeSize))
173                    throw BinException("Section offset+size out of range!");
174            if (ULEV(shdr.sh_link) >= ULEV(ehdr->e_shnum))
175                throw BinException("Section link out of range!");
176           
177            const typename Types::Size sh_nameindx = ULEV(shdr.sh_name);
178            if (sh_nameindx >= ULEV(shstrShdr.sh_size))
179                throw BinException("Section name index out of range!");
180           
181            if (sh_nameindx >= unfinishedShstrPos)
182                throw BinException("Unfinished section name!");
183           
184            const char* shname =
185                reinterpret_cast<const char*>(sectionStringTable + sh_nameindx);
186           
187            if ((creationFlags & ELF_CREATE_SECTIONMAP) != 0)
188                sectionIndexMap[i] = std::make_pair(shname, i);
189            // set symbol table and dynamic symbol table pointers
190            if (ULEV(shdr.sh_type) == SHT_SYMTAB)
191                symTableHdr = &shdr;
192            if (ULEV(shdr.sh_type) == SHT_DYNSYM)
193                dynSymTableHdr = &shdr;
194            if (ULEV(shdr.sh_type) == SHT_NOTE)
195                noteTableHdr = &shdr;
196            if (ULEV(shdr.sh_type) == SHT_DYNAMIC)
197                dynamicTableHdr = &shdr;
198        }
199        // sort section's map (really is array of sections)
200        if ((creationFlags & ELF_CREATE_SECTIONMAP) != 0)
201            mapSort(sectionIndexMap.begin(), sectionIndexMap.end(), CStringLess());
202       
203        if (symTableHdr != nullptr)
204        {
205            // indexing symbols
206            if (ULEV(symTableHdr->sh_entsize) < sizeof(typename Types::Sym))
207                throw BinException("SymTable entry size is too small!");
208           
209            symbolEntSize = ULEV(symTableHdr->sh_entsize);
210            symbolTable = binaryCode + ULEV(symTableHdr->sh_offset);
211            if (ULEV(symTableHdr->sh_link) == SHN_UNDEF)
212                throw BinException("Symbol table doesn't have string table");
213           
214            typename Types::Shdr& symstrShdr = getSectionHeader(ULEV(symTableHdr->sh_link));
215            symbolStringTable = binaryCode + ULEV(symstrShdr.sh_offset);
216           
217            const size_t unfinishedSymstrPos = unfinishedRegionOfStringTable(
218                    symbolStringTable, ULEV(symstrShdr.sh_size));
219            symbolsNum = ULEV(symTableHdr->sh_size)/ULEV(symTableHdr->sh_entsize);
220            if ((creationFlags & ELF_CREATE_SYMBOLMAP) != 0)
221                symbolIndexMap.resize(symbolsNum);
222           
223            for (typename Types::Size i = 0; i < symbolsNum; i++)
224            {
225                /* verify symbol names */
226                const typename Types::Sym& sym = getSymbol(i);
227                const typename Types::Size symnameindx = ULEV(sym.st_name);
228                if (symnameindx >= ULEV(symstrShdr.sh_size))
229                    throw BinException("Symbol name index out of range!");
230                // check whether name is finished in string section content
231                if (symnameindx >= unfinishedSymstrPos)
232                    throw BinException("Unfinished symbol name!");
233               
234                const char* symname =
235                    reinterpret_cast<const char*>(symbolStringTable + symnameindx);
236                // add to symbol map
237                if ((creationFlags & ELF_CREATE_SYMBOLMAP) != 0)
238                    symbolIndexMap[i] = std::make_pair(symname, i);
239            }
240            // sort symbol's map (really is array of symbols)
241            if ((creationFlags & ELF_CREATE_SYMBOLMAP) != 0)
242                mapSort(symbolIndexMap.begin(), symbolIndexMap.end(), CStringLess());
243        }
244        if (dynSymTableHdr != nullptr)
245        {
246            // indexing dynamic symbols
247            if (ULEV(dynSymTableHdr->sh_entsize) < sizeof(typename Types::Sym))
248                throw BinException("DynSymTable entry size is too small!");
249           
250            dynSymEntSize = ULEV(dynSymTableHdr->sh_entsize);
251            dynSymTable = binaryCode + ULEV(dynSymTableHdr->sh_offset);
252            if (ULEV(dynSymTableHdr->sh_link) == SHN_UNDEF)
253                throw BinException("DynSymbol table doesn't have string table");
254           
255            typename Types::Shdr& dynSymstrShdr =
256                    getSectionHeader(ULEV(dynSymTableHdr->sh_link));
257            dynSymbolsNum = ULEV(dynSymTableHdr->sh_size)/ULEV(dynSymTableHdr->sh_entsize);
258           
259            dynSymStringTable = binaryCode + ULEV(dynSymstrShdr.sh_offset);
260            const size_t unfinishedSymstrPos = unfinishedRegionOfStringTable(
261                    dynSymStringTable, ULEV(dynSymstrShdr.sh_size));
262           
263            if ((creationFlags & ELF_CREATE_DYNSYMMAP) != 0)
264                dynSymIndexMap.resize(dynSymbolsNum);
265           
266            for (typename Types::Size i = 0; i < dynSymbolsNum; i++)
267            {
268                /* verify symbol names */
269                const typename Types::Sym& sym = getDynSymbol(i);
270                const typename Types::Size symnameindx = ULEV(sym.st_name);
271                if (symnameindx >= ULEV(dynSymstrShdr.sh_size))
272                    throw BinException("DynSymbol name index out of range!");
273                // check whether name is finished in string section content
274                if (symnameindx >= unfinishedSymstrPos)
275                    throw BinException("Unfinished dynsymbol name!");
276               
277                const char* symname =
278                    reinterpret_cast<const char*>(dynSymStringTable + symnameindx);
279                // add to symbol map
280                if ((creationFlags & ELF_CREATE_DYNSYMMAP) != 0)
281                    dynSymIndexMap[i] = std::make_pair(symname, i);
282            }
283            // sort dynamic symbol's map (really is array of dynamic symbols)
284            if ((creationFlags & ELF_CREATE_DYNSYMMAP) != 0)
285                mapSort(dynSymIndexMap.begin(), dynSymIndexMap.end(), CStringLess());
286        }
287        if (noteTableHdr != nullptr)
288        {
289            noteTable = binaryCode + ULEV(noteTableHdr->sh_offset);
290            noteTableSize = ULEV(noteTableHdr->sh_size);
291        }
292        if (dynamicTableHdr != nullptr)
293        {
294            dynamicTable = binaryCode + ULEV(dynamicTableHdr->sh_offset);
295            const typename Types::Size entSize = ULEV(dynamicTableHdr->sh_entsize);
296            const typename Types::Size size = ULEV(dynamicTableHdr->sh_size);
297            if (entSize < sizeof(typename Types::Dyn))
298                throw BinException("Size of dynamic entry is too small!");
299            if (size % entSize != 0)
300                throw BinException("Size of dynamic section is not match!");
301            dynamicsNum = entSize / size;
302            dynamicEntSize = entSize;
303        }
304    }
305}
306
307template<typename Types>
308uint16_t ElfBinaryTemplate<Types>::getSectionIndex(const char* name) const
309{
310    if (hasSectionMap())
311    {
312        // find in section map (sorted array)
313        SectionIndexMap::const_iterator it = binaryMapFind(
314                    sectionIndexMap.begin(), sectionIndexMap.end(), name, CStringLess());
315        if (it == sectionIndexMap.end())
316            throw BinException(std::string("Can't find Elf")+Types::bitName+" Section");
317        return it->second;
318    }
319    else
320    {
321        // find in section headers (fallback)
322        for (cxuint i = 0; i < getSectionHeadersNum(); i++)
323        {
324            if (::strcmp(getSectionName(i), name) == 0)
325                return i;
326        }
327        throw BinException(std::string("Can't find Elf")+Types::bitName+" Section");
328    }
329}
330
331template<typename Types>
332typename Types::Size ElfBinaryTemplate<Types>::getSymbolIndex(const char* name) const
333{
334    SymbolIndexMap::const_iterator it = binaryMapFind(
335                    symbolIndexMap.begin(), symbolIndexMap.end(), name, CStringLess());
336    if (it == symbolIndexMap.end())
337        throw BinException(std::string("Can't find Elf")+Types::bitName+" Symbol");
338    return it->second;
339}
340
341template<typename Types>
342typename Types::Size ElfBinaryTemplate<Types>::getDynSymbolIndex(const char* name) const
343{
344    SymbolIndexMap::const_iterator it = binaryMapFind(
345                    dynSymIndexMap.begin(), dynSymIndexMap.end(), name, CStringLess());
346    if (it == dynSymIndexMap.end())
347        throw BinException(std::string("Can't find Elf")+Types::bitName+" DynSymbol");
348    return it->second;
349}
350
351template class CLRX::ElfBinaryTemplate<CLRX::Elf32Types>;
352template class CLRX::ElfBinaryTemplate<CLRX::Elf64Types>;
353
354bool CLRX::isElfBinary(size_t binarySize, const cxbyte* binary)
355{
356    if (binarySize < sizeof(Elf32_Ehdr) ||
357        ULEV(*reinterpret_cast<const uint32_t*>(binary)) != elfMagicValue)
358        return false;
359    if ((binary[EI_CLASS] != ELFCLASS32 && binary[EI_CLASS] != ELFCLASS64) ||
360        binary[EI_DATA] != ELFDATA2LSB) // only LSB elf is supported
361        return false;
362    // binary must be greater than ELF header
363    if ((binary[EI_CLASS] == ELFCLASS32 && binarySize < sizeof(Elf32_Ehdr)) ||
364        (binary[EI_CLASS] == ELFCLASS64 && binarySize < sizeof(Elf64_Ehdr)))
365        return false;
366    if (ULEV(*((const uint64_t*)(binary+8))) != 0)
367        return false;
368    return true;
369}
370
371/*
372 * Elf binary generator
373 */
374
375uint16_t CLRX::convertSectionId(cxuint sectionIndex, const uint16_t* builtinSections,
376                  cxuint maxBuiltinSection, cxuint extraSectionIndex)
377{
378    if (sectionIndex == ELFSECTID_NULL)
379        return 0;
380    if (sectionIndex == ELFSECTID_ABS)
381        return SHN_ABS;
382    if (sectionIndex == ELFSECTID_UNDEF)
383        return SHN_UNDEF;
384    if (sectionIndex < ELFSECTID_START)
385        return sectionIndex+extraSectionIndex;
386    else if (sectionIndex >= ELFSECTID_START && sectionIndex <= maxBuiltinSection)
387    {
388        const uint16_t shndx = builtinSections[sectionIndex-ELFSECTID_START];
389        if (shndx == SHN_UNDEF) // if table entry for sectionIndex is not defined
390            throw BinGenException("Wrong BinSection:sectionId");
391        return builtinSections[sectionIndex-ELFSECTID_START];
392    }
393    else // failed
394        throw BinGenException("Wrong BinSection:sectionId");
395}
396
397ElfRegionContent::~ElfRegionContent()
398{ }
399
400template<typename Types>
401static std::unique_ptr<uint32_t[]> calculateHashValuesForSymbols(bool addNullSymbol,
402            const std::vector<ElfSymbolTemplate<Types> >& symbols)
403{
404    const size_t symsNum = symbols.size() + addNullSymbol;
405    std::unique_ptr<uint32_t[]> hashCodes(new uint32_t[symsNum]);
406    if (addNullSymbol)
407        hashCodes[0] = 0;
408    for (size_t i = 0; i < symbols.size(); i++)
409    {
410        // main routine of hash
411        uint32_t h = 0, g;
412        const cxbyte* name = reinterpret_cast<const cxbyte*>(symbols[i].name);
413        while(*name!=0)
414        {
415            h = (h<<4) + *name++;
416            g = h & 0xf0000000U;
417            if (g) h ^= g>>24;
418            h &= ~g;
419        }
420        hashCodes[i+addNullSymbol] = h;
421    }
422    return hashCodes;
423}
424
425/// return bucket number
426static uint32_t optimizeHashBucketsNum(uint32_t hashNum, bool skipFirst,
427                           const uint32_t* hashCodes)
428{
429    uint32_t bestBucketNum = 0;
430    uint64_t bestValue = UINT64_MAX;
431    uint32_t firstStep = std::max(uint32_t(hashNum>>2), 1U);
432    uint64_t maxSteps = (uint64_t(hashNum)<<1) - (firstStep) + 1;
433    // limit step of optimizations to 4000
434    const uint32_t steps = std::min(maxSteps, uint64_t(4000U));
435   
436    std::unique_ptr<uint32_t[]> chainLengths(new uint32_t[(hashNum<<2)+1]);
437    const uint32_t stepSize = maxSteps / steps;
438    for (uint32_t buckets = firstStep; buckets <= (hashNum<<1); buckets += stepSize)
439    {   //
440        std::fill(chainLengths.get(), chainLengths.get() + buckets, 0U);
441        // calculate chain lengths
442        for (size_t i = skipFirst; i < hashNum; i++)
443            chainLengths[hashCodes[i] % buckets]++;
444        /// value, smaller is better
445        uint64_t value = uint64_t(buckets);
446        for (uint32_t i = 0; i < buckets; i++)
447            value += chainLengths[i]*chainLengths[i];
448        if (value < bestValue)
449        {
450            bestBucketNum = buckets;
451            bestValue = value;
452        }
453    }
454    return bestBucketNum;
455}
456
457template<typename Types>
458ElfBinaryGenTemplate<Types>::ElfBinaryGenTemplate()
459        : sizeComputed(false), addNullSym(true), addNullDynSym(true), addNullSection(true),
460          addrStartRegion(0), shStrTab(0), strTab(0), dynStr(0), shdrTabRegion(0),
461          phdrTabRegion(0), bucketsNum(0), isHashDynSym(false)
462{ }
463
464template<typename Types>
465ElfBinaryGenTemplate<Types>::ElfBinaryGenTemplate(const ElfHeaderTemplate<Types>& _header,
466            bool _addNullSym, bool _addNullDynSym, bool _addNullSection,
467            cxuint addrCountingFromRegion)
468        : sizeComputed(false), addNullSym(_addNullSym), addNullDynSym(_addNullDynSym),
469          addNullSection(_addNullSection),  addrStartRegion(addrCountingFromRegion),
470          shStrTab(0), strTab(0), dynStr(0), shdrTabRegion(0), phdrTabRegion(0),
471          header(_header), bucketsNum(0), isHashDynSym(false)
472{ }
473
474template<typename Types>
475void ElfBinaryGenTemplate<Types>::addRegion(const ElfRegionTemplate<Types>& region)
476{ regions.push_back(region); }
477
478template<typename Types>
479void ElfBinaryGenTemplate<Types>::addProgramHeader(
480            const ElfProgramHeaderTemplate<Types>& progHeader)
481{ progHeaders.push_back(progHeader); }
482
483static const int32_t dynTableSize = DT_NUM;
484
485
486template<typename Types>
487static inline typename Types::Word resolveSectionAddress(
488        const ElfHeaderTemplate<Types>& header, const ElfRegionTemplate<Types>& region2,
489        typename Types::Word regionAddr)
490{
491    /* addrBase is base address of first section. if not defined
492     * use address base as virtual address base from elf header */
493    if (region2.section.addrBase==Types::nobase)
494        return regionAddr;
495    else if (region2.section.addrBase != 0)
496        return region2.section.addrBase+regionAddr;
497    else if (header.vaddrBase != 0)
498        return header.vaddrBase+regionAddr;
499    else
500        return 0;
501}
502
503template<typename Types>
504void ElfBinaryGenTemplate<Types>::computeSize()
505{
506    if (sizeComputed) return;
507   
508    /* verify data */
509    if (header.entryRegion != UINT_MAX && header.entryRegion >= regions.size())
510        throw BinGenException("Header entry region out of range");
511   
512    regionOffsets.reset(new typename Types::Word[regions.size()]);
513    regionAddresses.reset(new typename Types::Word[regions.size()]);
514    size = sizeof(typename Types::Ehdr);
515    sectionsNum = addNullSection; // if add null section
516    cxuint hashSymSectionIdx = UINT_MAX;
517    bool haveDynamic = false;
518    for (const auto& region: regions)
519        if (region.type == ElfRegionType::SECTION)
520        {
521            if (region.section.type==SHT_HASH)
522                hashSymSectionIdx = region.section.link;
523            else if (region.section.type==SHT_DYNAMIC)
524                haveDynamic = true;
525            sectionsNum++;
526        }
527   
528    /// determine symbol name
529    cxuint sectionCount = addNullSection;
530    isHashDynSym = false;
531    if (hashSymSectionIdx!=UINT_MAX)
532    {
533        bool hashSymDetected = false;
534        // find hash symbol (or dynsymbol) section
535        for (const auto& region: regions)
536            if (region.type == ElfRegionType::SECTION)
537            {
538                if (hashSymSectionIdx==sectionCount)
539                {
540                    // get symbol section
541                    if (region.section.type==SHT_SYMTAB)
542                    {
543                        isHashDynSym = false;
544                        hashSymDetected = true;
545                    }
546                    else if (region.section.type==SHT_DYNSYM)
547                    {
548                        isHashDynSym = true;
549                        hashSymDetected = true;
550                    }
551                    else
552                        throw BinGenException("Wrong Hash Sym section!");
553                }
554                sectionCount++;
555            }
556        if (!hashSymDetected)
557            throw BinGenException("Wrong Hash Sym is not detected!");
558    }
559   
560    sectionRegions.reset(new cxuint[sectionsNum+1]);
561    // first section can be null, if not null section provided this will be filed later
562    sectionRegions[0] = UINT_MAX;
563    sectionCount = addNullSection;
564    typename Types::Word address = (addrStartRegion==PHREGION_FILESTART) ? size : 0;
565   
566    std::unique_ptr<typename Types::Word[]> dynValTable;
567    if (haveDynamic)
568    {
569        // prepare dynamic structures
570        dynamicValues.reset(new typename Types::Word[dynamics.size()]);
571        dynValTable.reset(new typename Types::Word[dynTableSize]);
572    }
573   
574    // verify symbol's sections (accepts SHN_ABS and SHN_UNDEF)
575    for (const auto& sym: symbols)
576        if (sym.sectionIndex >= sectionsNum && sym.sectionIndex!=SHN_ABS &&
577                    sym.sectionIndex!=SHN_UNDEF)
578            throw BinGenException("Symbol section index out of range");
579    for (const auto& sym: dynSymbols)
580        if (sym.sectionIndex >= sectionsNum && sym.sectionIndex!=SHN_ABS &&
581                    sym.sectionIndex!=SHN_UNDEF)
582            throw BinGenException("DynSymbol section index out of range");
583   
584    for (size_t i = 0; i < regions.size(); i++)
585    {
586        ElfRegionTemplate<Types>& region = regions[i];
587        if (region.align > 1)
588        {
589            // fix alignment
590            if ((size&(region.align-1))!=0)
591                size += region.align - (size&(region.align-1));
592            if ((address&(region.align-1))!=0)
593                address += region.align - (address&(region.align-1));
594        }
595       
596        regionOffsets[i] = size;
597        regionAddresses[i] = address;
598        // add region size
599        if (region.type == ElfRegionType::PHDR_TABLE)
600        {
601            size += uint64_t(progHeaders.size())*sizeof(typename Types::Phdr);
602            region.size = size-regionOffsets[i];
603            phdrTabRegion = i;
604            // checking program header ranges
605            for (const auto& progHdr: progHeaders)
606            {
607                if (progHdr.regionStart!=PHREGION_FILESTART &&
608                            progHdr.regionStart >= regions.size())
609                    throw BinGenException("Region start out of range");
610                if ((progHdr.regionStart==PHREGION_FILESTART &&
611                     progHdr.regionsNum > regions.size()) ||
612                    (progHdr.regionStart!=PHREGION_FILESTART &&
613                     uint64_t(progHdr.regionStart) + progHdr.regionsNum > regions.size()))
614                    throw BinGenException("Region end out of range");
615            }
616            if (addrStartRegion==PHREGION_FILESTART)
617                address = size;
618        }
619        else if (region.type == ElfRegionType::SHDR_TABLE)
620        {
621            size += uint64_t(sectionsNum)*sizeof(typename Types::Shdr);
622            region.size = size-regionOffsets[i];
623            shdrTabRegion = i;
624            if (addrStartRegion==PHREGION_FILESTART)
625                address = size;
626        }
627        else if (region.type == ElfRegionType::USER)
628        {
629            if (addrStartRegion==PHREGION_FILESTART)
630                address = size;
631            size += region.size;
632        }
633        else if (region.type == ElfRegionType::SECTION)
634        {
635            // if section
636            if (region.section.link >= sectionsNum)
637                throw BinGenException("Section link out of range");
638           
639            if (haveDynamic)
640            {
641                switch(region.section.type)
642                {
643                    case SHT_DYNSYM:
644                        dynValTable[DT_SYMTAB] = resolveSectionAddress(header, region,
645                                   regionAddresses[i]);
646                        dynValTable[DT_SYMENT] = sizeof(typename Types::Sym);
647                        break;
648                    case SHT_STRTAB:
649                        if (::strcmp(region.section.name, ".dynstr")==0)
650                            dynValTable[DT_STRTAB] = resolveSectionAddress(header, region,
651                                   regionAddresses[i]);
652                        break;
653                    case SHT_HASH:
654                        dynValTable[DT_HASH] = resolveSectionAddress(header, region,
655                                 regionAddresses[i]);
656                        break;
657                }
658            }
659           
660            if (region.section.type != SHT_NOBITS && region.size != 0)
661                size += region.size;
662            else
663            {
664                // otherwise get default size for symtab, dynsym, strtab, dynstr
665                if (region.section.type == SHT_SYMTAB)
666                    size += uint64_t(symbols.size()+addNullSym)*
667                                sizeof(typename Types::Sym);
668                else if (region.section.type == SHT_DYNSYM)
669                    size += uint64_t(dynSymbols.size()+addNullDynSym)*
670                                sizeof(typename Types::Sym);
671                else if (region.section.type == SHT_HASH)
672                {
673                    const std::vector<ElfSymbolTemplate<Types> >& hashSymbols = 
674                        (isHashDynSym) ? dynSymbols : symbols;
675                    bool addNullHashSym = (isHashDynSym) ? addNullDynSym : addNullSym;
676                    // calculating hashes of symbols and optimizing hash buckets
677                    hashCodes = calculateHashValuesForSymbols(addNullDynSym, hashSymbols);
678                    bucketsNum = optimizeHashBucketsNum(hashSymbols.size()+addNullHashSym,
679                           addNullHashSym, hashCodes.get());
680                    // and add these hash size to size
681                    size += 4*(bucketsNum + hashSymbols.size()+addNullHashSym + 2);
682                }
683                else if (region.section.type == SHT_DYNAMIC)
684                    size += (dynamics.size()+1) * sizeof(typename Types::Dyn);
685                else if (region.section.type == SHT_NOTE)
686                {
687                    for (const ElfNote& note: notes)
688                    {
689                        // note size with data
690                        size_t nameSize = ::strlen(note.name)+1;
691                        if ((nameSize&3)!=0)
692                            nameSize += 4 - (nameSize&3);
693                        size_t descSize = note.descSize;
694                        if ((descSize&3)!=0)
695                            descSize += 4 - (descSize&3);
696                        size += sizeof(typename Types::Nhdr) + nameSize + descSize;
697                    }
698                }
699                else if (region.section.type == SHT_STRTAB)
700                {
701                    if (::strcmp(region.section.name, ".strtab") == 0)
702                    {
703                        size += (addNullSym);
704                        for (const auto& sym: symbols)
705                            if (sym.name != nullptr && sym.name[0] != 0)
706                                size += ::strlen(sym.name)+1;
707                    }
708                    else if (::strcmp(region.section.name, ".dynstr") == 0)
709                    {
710                        size += (addNullDynSym);
711                        for (const auto& sym: dynSymbols)
712                            if (sym.name != nullptr && sym.name[0] != 0)
713                                size += ::strlen(sym.name)+1;
714                    }
715                    else if (::strcmp(region.section.name, ".shstrtab") == 0)
716                    {
717                        size += (addNullSection);
718                        for (const auto& region2: regions)
719                        {
720                            if (region2.type == ElfRegionType::SECTION &&
721                                region2.section.name != nullptr &&
722                                region2.section.name[0] != 0)
723                                size += ::strlen(region2.section.name)+1;
724                        }
725                    }
726                }
727                if (region.section.type != SHT_NOBITS)
728                    region.size = size-regionOffsets[i];
729            }
730            if (addrStartRegion==PHREGION_FILESTART)
731                address = size;
732            else if (i >= addrStartRegion) // begin counting address from that region
733                address += region.size;
734           
735            if (haveDynamic)
736            {
737                if (region.section.type == SHT_STRTAB &&
738                    ::strcmp(region.section.name, ".dynstr") == 0)
739                    dynValTable[DT_STRSZ] = region.size;
740            }
741           
742            if (::strcmp(region.section.name, ".strtab") == 0)
743                strTab = sectionCount;
744            else if (::strcmp(region.section.name, ".dynstr") == 0)
745                dynStr = sectionCount;
746            else if (::strcmp(region.section.name, ".shstrtab") == 0)
747                shStrTab = sectionCount;
748            sectionRegions[sectionCount] = i;
749            sectionCount++;
750        }
751    }
752   
753    if (haveDynamic)
754    {
755        // set dynamic values
756        for (size_t i = 0; i < dynamics.size(); i++)
757            if (dynamics[i] >= 0 && dynamics[i] < dynTableSize)
758                dynamicValues[i] = dynValTable[dynamics[i]];
759    }
760   
761    sizeComputed = true;
762}
763
764template<typename Types>
765uint64_t ElfBinaryGenTemplate<Types>::countSize()
766{
767    computeSize();
768    return size;
769}
770
771// create hash table, really bucket chains and fill buckets
772static void createHashTable(uint32_t bucketsNum, uint32_t hashNum, bool skipFirst,
773                           const uint32_t* hashCodes, uint32_t* output)
774{
775    SLEV(output[0], bucketsNum);
776    SLEV(output[1], hashNum);
777    uint32_t* buckets = output + 2;
778    uint32_t* chains = output + bucketsNum + 2;
779    std::fill(buckets, buckets + bucketsNum, 0U);
780    std::fill(chains, chains + hashNum, STN_UNDEF);
781   
782    std::unique_ptr<uint32_t[]> lastNodes(new uint32_t[bucketsNum]);
783    std::fill(lastNodes.get(), lastNodes.get() + bucketsNum, UINT32_MAX);
784    for (uint32_t i = skipFirst; i < hashNum; i++)
785    {
786        const uint32_t bucket = hashCodes[i] % bucketsNum;
787        if (lastNodes[bucket] == UINT32_MAX)
788        {
789            // first entry of chain
790            SLEV(buckets[bucket], i);
791            lastNodes[bucket] = i;
792        }
793        else
794        {
795            SLEV(chains[lastNodes[bucket]], i);
796            lastNodes[bucket] = i;
797        }
798    }
799}
800
801template<typename Types>
802void ElfBinaryGenTemplate<Types>::generate(FastOutputBuffer& fob)
803{
804    computeSize();
805    const uint64_t startOffset = fob.getWritten();
806    /* write elf header */
807    {
808        typename Types::Ehdr ehdr;
809        ::memset(ehdr.e_ident, 0, EI_NIDENT);
810        ehdr.e_ident[0] = 0x7f;
811        ehdr.e_ident[1] = 'E';
812        ehdr.e_ident[2] = 'L';
813        ehdr.e_ident[3] = 'F';
814        ehdr.e_ident[4] = Types::ELFCLASS;
815        ehdr.e_ident[5] = ELFDATA2LSB;
816        ehdr.e_ident[6] = EV_CURRENT;
817        ehdr.e_ident[EI_OSABI] = header.osABI;
818        ehdr.e_ident[EI_ABIVERSION] = header.abiVersion;
819        SLEV(ehdr.e_type, header.type);
820        SLEV(ehdr.e_machine, header.machine);
821        SLEV(ehdr.e_version, header.version);
822        SLEV(ehdr.e_flags, header.flags);
823        if (header.entryRegion != UINT_MAX)
824        {
825            // if have entry
826            typename Types::Word entry = regionOffsets[header.entryRegion] + header.entry;
827            if (regions[header.entryRegion].type == ElfRegionType::SECTION &&
828                regions[header.entryRegion].section.addrBase != 0)
829                entry += regions[header.entryRegion].section.addrBase;
830            else
831                entry += header.vaddrBase;
832           
833            SLEV(ehdr.e_entry, entry);
834        }
835        else
836            SLEV(ehdr.e_entry, 0);
837        SLEV(ehdr.e_ehsize, sizeof(typename Types::Ehdr));
838        // if no program headers then fill by zeroes, otherwise fill fields
839        if (!progHeaders.empty())
840        {
841            SLEV(ehdr.e_phentsize, sizeof(typename Types::Phdr));
842            SLEV(ehdr.e_phoff, regionOffsets[phdrTabRegion]);
843        }
844        else
845        {
846            SLEV(ehdr.e_phentsize, 0);
847            SLEV(ehdr.e_phoff, 0);
848        }
849        SLEV(ehdr.e_phnum, progHeaders.size());
850        SLEV(ehdr.e_shentsize, sizeof(typename Types::Shdr));
851        SLEV(ehdr.e_shnum, sectionsNum);
852        SLEV(ehdr.e_shoff, regionOffsets[shdrTabRegion]);
853        SLEV(ehdr.e_shstrndx, shStrTab);
854       
855        fob.writeObject(ehdr);
856    }
857   
858    size_t nullSymNameOffset = 0;
859    // if addNullSym is not set, then no empty symbol name added, then we
860    // find first null character
861    if (!addNullSym && !symbols.empty())
862        nullSymNameOffset = ::strlen(symbols[0].name);
863    size_t nullDynSymNameOffset = 0;
864    // if addNullDynSym is not set, then no empty dynamic symbol name added, then we
865    // find first null character
866    if (!addNullDynSym && !dynSymbols.empty())
867        nullDynSymNameOffset = ::strlen(dynSymbols[0].name);
868    // if addNullSection is not set, then no empty section name added, then we
869    // find first null character
870    size_t nullSectionNameOffset = 0;
871    if (!addNullSection)
872    {
873        for (const ElfRegionTemplate<Types>& reg: regions)
874            if (reg.type == ElfRegionType::SECTION)
875            {
876                nullSectionNameOffset = ::strlen(reg.section.name);
877                break;
878            }
879    }
880   
881    /* write regions */
882    for (size_t i = 0; i < regions.size(); i++)
883    {   
884        const ElfRegionTemplate<Types>& region = regions[i];
885        // fix alignment
886        uint64_t toFill = 0;
887        typename Types::Word ralign = (region.type==ElfRegionType::SECTION) ?
888                        region.section.align : 0;
889        ralign = std::max(region.align, ralign);
890        if (ralign > 1)
891        {
892            const uint64_t curOffset = (fob.getWritten()-startOffset);
893            if (ralign!=0 && (curOffset&(ralign-1))!=0)
894                toFill = ralign - (curOffset&(ralign-1));
895            fob.fill(toFill, 0);
896        }
897        assert(regionOffsets[i] == fob.getWritten()-startOffset);
898       
899        // write content
900        if (region.type == ElfRegionType::PHDR_TABLE)
901        {
902            /* write program headers */
903            for (const auto& progHeader: progHeaders)
904            {
905                typename Types::Phdr phdr;
906                SLEV(phdr.p_type, progHeader.type);
907                SLEV(phdr.p_flags, progHeader.flags);
908                const ElfRegionTemplate<Types> startRegion(sizeof(typename Types::Ehdr),
909                        (const cxbyte*)nullptr, sizeof(typename Types::Word));
910                // get first region of program header and it offset, index and address
911                const ElfRegionTemplate<Types>& sregion = 
912                        (progHeader.regionStart==PHREGION_FILESTART) ? startRegion :
913                        regions[progHeader.regionStart];
914                const cxuint rstart = (progHeader.regionStart!=PHREGION_FILESTART) ?
915                            progHeader.regionStart : 0;
916                const typename Types::Word sroffset =
917                        (progHeader.regionStart!=PHREGION_FILESTART) ?
918                            regionOffsets[progHeader.regionStart] : 0;
919                const typename Types::Word sraddress =
920                        (progHeader.regionStart!=PHREGION_FILESTART) ?
921                            regionAddresses[progHeader.regionStart] : 0;
922               
923                // zero offset, allow to set zero offset of section
924                bool zeroOffset = sregion.type == ElfRegionType::SECTION &&
925                        sregion.section.zeroOffset;
926                SLEV(phdr.p_offset, !zeroOffset ? sroffset : 0);
927                if (progHeader.align==0 && progHeader.regionsNum==0)
928                    SLEV(phdr.p_align, 0);
929                else if (progHeader.align==0)
930                {
931                    typename Types::Word align = (sregion.type==ElfRegionType::SECTION) ?
932                            sregion.section.align : 0;
933                    align = std::max(sregion.align, align);
934                    SLEV(phdr.p_align, align);
935                }
936                else
937                    SLEV(phdr.p_align, progHeader.align);
938               
939                /* paddrBase and vaddrBase is base to program header virtual and physical
940                 * addresses for program header. if not defined then get address base
941                 * from ELF header */
942                if (progHeader.paddrBase == Types::nobase)
943                    SLEV(phdr.p_paddr, sraddress);
944                else if (progHeader.paddrBase != 0)
945                    SLEV(phdr.p_paddr, progHeader.paddrBase + sraddress);
946                else if (header.paddrBase != 0)
947                    SLEV(phdr.p_paddr, header.paddrBase + sraddress);
948                else
949                    SLEV(phdr.p_paddr, 0);
950               
951                // these same rule for vaddrBase
952                if (progHeader.vaddrBase == Types::nobase)
953                    SLEV(phdr.p_vaddr, sraddress);
954                else if (progHeader.vaddrBase != 0)
955                    SLEV(phdr.p_vaddr, progHeader.vaddrBase + sraddress);
956                else if (header.vaddrBase != 0)
957                    SLEV(phdr.p_vaddr, header.vaddrBase + sraddress);
958                else
959                    SLEV(phdr.p_vaddr, 0);
960               
961                // last region size for file - if nobits section then we assume zero size
962                if (progHeader.regionsNum!=0)
963                {
964                    const auto& lastReg = regions[rstart + progHeader.regionsNum-1];
965                    uint64_t fileLastRegSize =(lastReg.type!=ElfRegionType::SECTION ||
966                        lastReg.section.type!=SHT_NOBITS) ? lastReg.size : 0;
967                    /// fileSize - add offset of first region to simulate region alignment
968                    const typename Types::Word fileSize = regionOffsets[rstart+
969                            progHeader.regionsNum-1] + fileLastRegSize - sroffset;
970                    const typename Types::Word phSize = regionAddresses[rstart+
971                            progHeader.regionsNum-1]+regions[rstart+
972                            progHeader.regionsNum-1].size - sraddress;
973                   
974                    if (progHeader.haveMemSize)
975                    {
976                        if (progHeader.memSize != 0)
977                            SLEV(phdr.p_memsz, progHeader.memSize);
978                        else
979                            SLEV(phdr.p_memsz, phSize);
980                    }
981                    else
982                        SLEV(phdr.p_memsz, 0);
983                    SLEV(phdr.p_filesz, fileSize);
984                }
985                else
986                {
987                    SLEV(phdr.p_memsz, 0);
988                    SLEV(phdr.p_filesz, 0);
989                }
990                fob.writeObject(phdr);
991            }
992        }
993        else if (region.type == ElfRegionType::SHDR_TABLE)
994        {
995            /* write section headers table */
996            if (addNullSection)
997                fob.fill(sizeof(typename Types::Shdr), 0);
998            uint32_t nameOffset = (addNullSection);
999            for (cxuint j = 0; j < regions.size(); j++)
1000            {
1001                const auto& region2 = regions[j];
1002                if (region2.type == ElfRegionType::SECTION)
1003                {
1004                    typename Types::Shdr shdr;
1005                    if (region2.section.name!=nullptr && region2.section.name[0]!=0)
1006                        SLEV(shdr.sh_name, nameOffset);
1007                    else // set empty name offset
1008                        SLEV(shdr.sh_name, nullSectionNameOffset);
1009                    SLEV(shdr.sh_type, region2.section.type);
1010                    SLEV(shdr.sh_flags, region2.section.flags);
1011                    SLEV(shdr.sh_offset, (!region2.section.zeroOffset) ?
1012                                regionOffsets[j] : 0);
1013                    SLEV(shdr.sh_addr, resolveSectionAddress(header, region2,
1014                                     regionAddresses[j]));
1015                   
1016                    if (region2.align != 0 || j+1 >= regions.size() ||
1017                        regionOffsets[j]+region2.size == regionOffsets[j+1])
1018                        SLEV(shdr.sh_size, region2.size);
1019                    else // otherwise if not match this size
1020                        SLEV(shdr.sh_size, regionOffsets[j+1]-regionOffsets[j]);
1021                   
1022                    if ((region2.section.type!=SHT_SYMTAB &&
1023                         region2.section.type!=SHT_DYNSYM) ||
1024                            region2.section.info != BINGEN_DEFAULT)
1025                        // put set info
1026                        SLEV(shdr.sh_info, region2.section.info);
1027                    else // if symbtabs
1028                    {
1029                        // otherwise if default for symtabs, put count of last local
1030                        const auto& symbolsList = (region2.section.type == SHT_SYMTAB) ?
1031                            symbols : dynSymbols;
1032                        cxuint lastLocal = 0;
1033                        for (size_t l = 0; l < symbolsList.size(); l++)
1034                            if (ELF32_ST_BIND(symbolsList[l].info)==STB_LOCAL)
1035                                lastLocal = l+1;
1036                        if ((region2.section.type==SHT_SYMTAB && addNullSym) ||
1037                            (region2.section.type==SHT_DYNSYM && addNullDynSym))
1038                            lastLocal++;
1039                        SLEV(shdr.sh_info, lastLocal);
1040                    }
1041                   
1042                    SLEV(shdr.sh_addralign, (region2.section.align==0) ?
1043                            region2.align : region2.section.align);
1044                    if (region2.section.link == 0)
1045                    {
1046                        // set up link (for symtab is .strtab for .dynsym is dynstr)
1047                        if (::strcmp(region2.section.name, ".symtab") == 0)
1048                            SLEV(shdr.sh_link, strTab);
1049                        else if (::strcmp(region2.section.name, ".dynsym") == 0)
1050                            SLEV(shdr.sh_link, dynStr);
1051                        else // otherwise is value is link (zero)
1052                            SLEV(shdr.sh_link, region2.section.link);
1053                    }
1054                    else
1055                        SLEV(shdr.sh_link, region2.section.link);
1056                   
1057                    // set up entry size for sections
1058                    if (region2.section.type == SHT_SYMTAB ||
1059                        region2.section.type == SHT_DYNSYM)
1060                        SLEV(shdr.sh_entsize, sizeof(typename Types::Sym));
1061                    else if (region2.section.type == SHT_DYNAMIC)
1062                        SLEV(shdr.sh_entsize, sizeof(typename Types::Dyn));
1063                    else // if not default
1064                        SLEV(shdr.sh_entsize, region2.section.entSize);
1065                    if (region2.section.name!=nullptr && region2.section.name[0]!=0)
1066                        nameOffset += ::strlen(region2.section.name)+1;
1067                    fob.writeObject(shdr);
1068                }
1069            }
1070        }
1071        else if (region.type == ElfRegionType::USER)
1072        {
1073            if (region.dataFromPointer)
1074                fob.writeArray(region.size, region.data);
1075            else
1076                (*region.dataGen)(fob);
1077        }
1078        else if (region.type == ElfRegionType::SECTION)
1079        {
1080            if (region.data == nullptr)
1081            {
1082                if (region.section.type == SHT_SYMTAB || region.section.type == SHT_DYNSYM)
1083                {
1084                    uint32_t nameOffset = 0;
1085                    // put null symbol if addNullSym or addNumDynSym is true
1086                    if (region.section.type == SHT_SYMTAB && addNullSym)
1087                    {
1088                        fob.fill(sizeof(typename Types::Sym), 0);
1089                        nameOffset = 1;
1090                    }
1091                    if (region.section.type == SHT_DYNSYM && addNullDynSym)
1092                    {
1093                        fob.fill(sizeof(typename Types::Sym), 0);
1094                        nameOffset = 1;
1095                    }
1096                    const auto& symbolsList = (region.section.type == SHT_SYMTAB) ?
1097                            symbols : dynSymbols;
1098                    for (const auto& inSym: symbolsList)
1099                    {
1100                        typename Types::Sym sym;
1101                        if (inSym.name != nullptr && inSym.name[0] != 0)
1102                            SLEV(sym.st_name, nameOffset);
1103                        else  // set empty name offset (symbol or dynamic symbol)
1104                            SLEV(sym.st_name, (region.section.type == SHT_SYMTAB) ?
1105                                        nullSymNameOffset : nullDynSymNameOffset);
1106                       
1107                        SLEV(sym.st_shndx, inSym.sectionIndex);
1108                        SLEV(sym.st_size, inSym.size);
1109                        /// if value defined as address
1110                        if (!inSym.valueIsAddr)
1111                            SLEV(sym.st_value, inSym.value);
1112                        // if not use conversion to address with section addrBase
1113                        else if ((inSym.sectionIndex != 0 || !addNullSection) &&
1114                                regions[sectionRegions[
1115                                    inSym.sectionIndex]].section.addrBase != 0)
1116                        {
1117                            // store symbol value as address or value
1118                            typename Types::Word addrBase = regions[sectionRegions[
1119                                    inSym.sectionIndex]].section.addrBase;
1120                            SLEV(sym.st_value, inSym.value + regionOffsets[
1121                                    sectionRegions[inSym.sectionIndex]] +
1122                                    (addrBase!=Types::nobase ? addrBase : 0));
1123                        }
1124                        else if (header.vaddrBase!=Types::nobase)
1125                            // use elf headerf virtual address base
1126                            SLEV(sym.st_value, inSym.value + regionOffsets[
1127                                sectionRegions[inSym.sectionIndex]] +
1128                                (header.vaddrBase!=Types::nobase ? header.vaddrBase : 0));
1129                        sym.st_other = inSym.other;
1130                        sym.st_info = inSym.info;
1131                        if (inSym.name != nullptr && inSym.name[0] != 0)
1132                            nameOffset += ::strlen(inSym.name)+1;
1133                        fob.writeObject(sym);
1134                    }
1135                }
1136                else if (region.section.type == SHT_DYNAMIC)
1137                {
1138                    // dynamic table
1139                    typename Types::Dyn dyn;
1140                    for (size_t k = 0; k < dynamics.size(); k++)
1141                    {
1142                        SLEV(dyn.d_tag, dynamics[k]);
1143                        SLEV(dyn.d_un.d_val, dynamicValues[k]);
1144                        fob.writeObject(dyn);
1145                    }
1146                    SLEV(dyn.d_tag, DT_NULL);
1147                    SLEV(dyn.d_un.d_val, 0U);
1148                    fob.writeObject(dyn);
1149                }
1150                else if (region.section.type == SHT_HASH)
1151                {
1152                    // creating hash table and put it
1153                    const std::vector<ElfSymbolTemplate<Types> >& hashSymbols = 
1154                        (isHashDynSym) ? dynSymbols : symbols;
1155                    bool addNullHashSym = (isHashDynSym) ? addNullDynSym : addNullSym;
1156                    Array<uint32_t> hashTable(2 + hashSymbols.size() + addNullHashSym +
1157                                bucketsNum);
1158                    createHashTable(bucketsNum, hashSymbols.size()+addNullHashSym,
1159                                addNullHashSym, hashCodes.get(), hashTable.data());
1160                    fob.writeArray(hashTable.size(), hashTable.data());
1161                }
1162                else if (region.section.type == SHT_NOTE)
1163                {
1164                    // putting ELF notes
1165                    for (const ElfNote& note: notes)
1166                    {
1167                        typename Types::Nhdr nhdr;
1168                        size_t nameSize = ::strlen(note.name)+1;
1169                        size_t descSize = note.descSize;
1170                        SLEV(nhdr.n_namesz, nameSize);
1171                        SLEV(nhdr.n_descsz, descSize);
1172                        SLEV(nhdr.n_type, note.type);
1173                        fob.writeObject(nhdr);
1174                        fob.write(nameSize, note.name);
1175                        if ((nameSize&3) != 0)
1176                            fob.fill(4 - (nameSize&3), 0);
1177                        fob.writeArray(descSize, note.desc);
1178                        if ((descSize&3) != 0)
1179                            fob.fill(4 - (descSize&3), 0);
1180                    }
1181                }
1182                else if (region.section.type == SHT_STRTAB)
1183                {
1184                    // put symbol names and section names
1185                    if (::strcmp(region.section.name, ".strtab") == 0)
1186                    {
1187                        if (addNullSym)
1188                            fob.put(0);
1189                        for (const auto& sym: symbols)
1190                            if (sym.name != nullptr && sym.name[0] != 0)
1191                                fob.write(::strlen(sym.name)+1, sym.name);
1192                    }
1193                    else if (::strcmp(region.section.name, ".dynstr") == 0)
1194                    {
1195                        if (addNullDynSym)
1196                            fob.put(0);
1197                        for (const auto& sym: dynSymbols)
1198                            if (sym.name != nullptr && sym.name[0] != 0)
1199                                fob.write(::strlen(sym.name)+1, sym.name);
1200                    }
1201                    else if (::strcmp(region.section.name, ".shstrtab") == 0)
1202                    {
1203                        if (addNullSection)
1204                            fob.put(0);
1205                        for (const auto& region2: regions)
1206                            if (region2.type == ElfRegionType::SECTION &&
1207                                region2.section.name != nullptr &&
1208                                region2.section.name[0] != 0)
1209                                fob.write(::strlen(region2.section.name)+1,
1210                                          region2.section.name);
1211                    }
1212                }
1213            }
1214            else if (region.section.type != SHT_NOBITS)
1215            {
1216                if (region.dataFromPointer)
1217                    fob.writeArray(region.size, region.data);
1218                else
1219                    (*region.dataGen)(fob);
1220            }
1221        }
1222    }
1223    fob.flush();
1224    fob.getOStream().flush();
1225    assert(size == fob.getWritten()-startOffset);
1226}
1227
1228template class CLRX::ElfBinaryGenTemplate<CLRX::Elf32Types>;
1229template class CLRX::ElfBinaryGenTemplate<CLRX::Elf64Types>;
Note: See TracBrowser for help on using the repository browser.