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

Last change on this file since 3759 was 3759, checked in by matszpk, 2 years ago

CLRadeonExtender: ElfBin?: Add new dynamics setup for relocations.

File size: 53.7 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                    case SHT_RELA:
658                        dynValTable[DT_RELA] = resolveSectionAddress(header, region,
659                                 regionAddresses[i]);
660                        dynValTable[DT_RELASZ] = region.size;
661                        dynValTable[DT_RELAENT] = sizeof(typename Types::Rela);
662                        break;
663                    case SHT_REL:
664                        dynValTable[DT_REL] = resolveSectionAddress(header, region,
665                                 regionAddresses[i]);
666                        dynValTable[DT_RELSZ] = region.size;
667                        dynValTable[DT_RELENT] = sizeof(typename Types::Rel);
668                        break;
669                }
670            }
671           
672            if (region.section.type != SHT_NOBITS && region.size != 0)
673                size += region.size;
674            else
675            {
676                // otherwise get default size for symtab, dynsym, strtab, dynstr
677                if (region.section.type == SHT_SYMTAB)
678                    size += uint64_t(symbols.size()+addNullSym)*
679                                sizeof(typename Types::Sym);
680                else if (region.section.type == SHT_DYNSYM)
681                    size += uint64_t(dynSymbols.size()+addNullDynSym)*
682                                sizeof(typename Types::Sym);
683                else if (region.section.type == SHT_HASH)
684                {
685                    const std::vector<ElfSymbolTemplate<Types> >& hashSymbols = 
686                        (isHashDynSym) ? dynSymbols : symbols;
687                    bool addNullHashSym = (isHashDynSym) ? addNullDynSym : addNullSym;
688                    // calculating hashes of symbols and optimizing hash buckets
689                    hashCodes = calculateHashValuesForSymbols(addNullDynSym, hashSymbols);
690                    bucketsNum = optimizeHashBucketsNum(hashSymbols.size()+addNullHashSym,
691                           addNullHashSym, hashCodes.get());
692                    // and add these hash size to size
693                    size += 4*(bucketsNum + hashSymbols.size()+addNullHashSym + 2);
694                }
695                else if (region.section.type == SHT_DYNAMIC)
696                    size += (dynamics.size()+1) * sizeof(typename Types::Dyn);
697                else if (region.section.type == SHT_NOTE)
698                {
699                    for (const ElfNote& note: notes)
700                    {
701                        // note size with data
702                        size_t nameSize = ::strlen(note.name)+1;
703                        if ((nameSize&3)!=0)
704                            nameSize += 4 - (nameSize&3);
705                        size_t descSize = note.descSize;
706                        if ((descSize&3)!=0)
707                            descSize += 4 - (descSize&3);
708                        size += sizeof(typename Types::Nhdr) + nameSize + descSize;
709                    }
710                }
711                else if (region.section.type == SHT_STRTAB)
712                {
713                    if (::strcmp(region.section.name, ".strtab") == 0)
714                    {
715                        size += (addNullSym);
716                        for (const auto& sym: symbols)
717                            if (sym.name != nullptr && sym.name[0] != 0)
718                                size += ::strlen(sym.name)+1;
719                    }
720                    else if (::strcmp(region.section.name, ".dynstr") == 0)
721                    {
722                        size += (addNullDynSym);
723                        for (const auto& sym: dynSymbols)
724                            if (sym.name != nullptr && sym.name[0] != 0)
725                                size += ::strlen(sym.name)+1;
726                    }
727                    else if (::strcmp(region.section.name, ".shstrtab") == 0)
728                    {
729                        size += (addNullSection);
730                        for (const auto& region2: regions)
731                        {
732                            if (region2.type == ElfRegionType::SECTION &&
733                                region2.section.name != nullptr &&
734                                region2.section.name[0] != 0)
735                                size += ::strlen(region2.section.name)+1;
736                        }
737                    }
738                }
739                if (region.section.type != SHT_NOBITS)
740                    region.size = size-regionOffsets[i];
741            }
742            if (addrStartRegion==PHREGION_FILESTART)
743                address = size;
744            else if (i >= addrStartRegion) // begin counting address from that region
745                address += region.size;
746           
747            if (haveDynamic)
748            {
749                // set dynamics
750                if (region.section.type == SHT_STRTAB &&
751                    ::strcmp(region.section.name, ".dynstr") == 0)
752                    dynValTable[DT_STRSZ] = region.size;
753            }
754           
755            if (::strcmp(region.section.name, ".strtab") == 0)
756                strTab = sectionCount;
757            else if (::strcmp(region.section.name, ".dynstr") == 0)
758                dynStr = sectionCount;
759            else if (::strcmp(region.section.name, ".shstrtab") == 0)
760                shStrTab = sectionCount;
761            sectionRegions[sectionCount] = i;
762            sectionCount++;
763        }
764    }
765   
766    if (haveDynamic)
767    {
768        // set dynamic values
769        for (size_t i = 0; i < dynamics.size(); i++)
770            if (dynamics[i] >= 0 && dynamics[i] < dynTableSize)
771                dynamicValues[i] = dynValTable[dynamics[i]];
772    }
773   
774    sizeComputed = true;
775}
776
777template<typename Types>
778uint64_t ElfBinaryGenTemplate<Types>::countSize()
779{
780    computeSize();
781    return size;
782}
783
784// create hash table, really bucket chains and fill buckets
785static void createHashTable(uint32_t bucketsNum, uint32_t hashNum, bool skipFirst,
786                           const uint32_t* hashCodes, uint32_t* output)
787{
788    SLEV(output[0], bucketsNum);
789    SLEV(output[1], hashNum);
790    uint32_t* buckets = output + 2;
791    uint32_t* chains = output + bucketsNum + 2;
792    std::fill(buckets, buckets + bucketsNum, 0U);
793    std::fill(chains, chains + hashNum, STN_UNDEF);
794   
795    std::unique_ptr<uint32_t[]> lastNodes(new uint32_t[bucketsNum]);
796    std::fill(lastNodes.get(), lastNodes.get() + bucketsNum, UINT32_MAX);
797    for (uint32_t i = skipFirst; i < hashNum; i++)
798    {
799        const uint32_t bucket = hashCodes[i] % bucketsNum;
800        if (lastNodes[bucket] == UINT32_MAX)
801        {
802            // first entry of chain
803            SLEV(buckets[bucket], i);
804            lastNodes[bucket] = i;
805        }
806        else
807        {
808            SLEV(chains[lastNodes[bucket]], i);
809            lastNodes[bucket] = i;
810        }
811    }
812}
813
814template<typename Types>
815void ElfBinaryGenTemplate<Types>::generate(FastOutputBuffer& fob)
816{
817    computeSize();
818    const uint64_t startOffset = fob.getWritten();
819    /* write elf header */
820    {
821        typename Types::Ehdr ehdr;
822        ::memset(ehdr.e_ident, 0, EI_NIDENT);
823        ehdr.e_ident[0] = 0x7f;
824        ehdr.e_ident[1] = 'E';
825        ehdr.e_ident[2] = 'L';
826        ehdr.e_ident[3] = 'F';
827        ehdr.e_ident[4] = Types::ELFCLASS;
828        ehdr.e_ident[5] = ELFDATA2LSB;
829        ehdr.e_ident[6] = EV_CURRENT;
830        ehdr.e_ident[EI_OSABI] = header.osABI;
831        ehdr.e_ident[EI_ABIVERSION] = header.abiVersion;
832        SLEV(ehdr.e_type, header.type);
833        SLEV(ehdr.e_machine, header.machine);
834        SLEV(ehdr.e_version, header.version);
835        SLEV(ehdr.e_flags, header.flags);
836        if (header.entryRegion != UINT_MAX)
837        {
838            // if have entry
839            typename Types::Word entry = regionOffsets[header.entryRegion] + header.entry;
840            if (regions[header.entryRegion].type == ElfRegionType::SECTION &&
841                regions[header.entryRegion].section.addrBase != 0)
842                entry += regions[header.entryRegion].section.addrBase;
843            else
844                entry += header.vaddrBase;
845           
846            SLEV(ehdr.e_entry, entry);
847        }
848        else
849            SLEV(ehdr.e_entry, 0);
850        SLEV(ehdr.e_ehsize, sizeof(typename Types::Ehdr));
851        // if no program headers then fill by zeroes, otherwise fill fields
852        if (!progHeaders.empty())
853        {
854            SLEV(ehdr.e_phentsize, sizeof(typename Types::Phdr));
855            SLEV(ehdr.e_phoff, regionOffsets[phdrTabRegion]);
856        }
857        else
858        {
859            SLEV(ehdr.e_phentsize, 0);
860            SLEV(ehdr.e_phoff, 0);
861        }
862        SLEV(ehdr.e_phnum, progHeaders.size());
863        SLEV(ehdr.e_shentsize, sizeof(typename Types::Shdr));
864        SLEV(ehdr.e_shnum, sectionsNum);
865        SLEV(ehdr.e_shoff, regionOffsets[shdrTabRegion]);
866        SLEV(ehdr.e_shstrndx, shStrTab);
867       
868        fob.writeObject(ehdr);
869    }
870   
871    size_t nullSymNameOffset = 0;
872    // if addNullSym is not set, then no empty symbol name added, then we
873    // find first null character
874    if (!addNullSym && !symbols.empty())
875        nullSymNameOffset = ::strlen(symbols[0].name);
876    size_t nullDynSymNameOffset = 0;
877    // if addNullDynSym is not set, then no empty dynamic symbol name added, then we
878    // find first null character
879    if (!addNullDynSym && !dynSymbols.empty())
880        nullDynSymNameOffset = ::strlen(dynSymbols[0].name);
881    // if addNullSection is not set, then no empty section name added, then we
882    // find first null character
883    size_t nullSectionNameOffset = 0;
884    if (!addNullSection)
885    {
886        for (const ElfRegionTemplate<Types>& reg: regions)
887            if (reg.type == ElfRegionType::SECTION)
888            {
889                nullSectionNameOffset = ::strlen(reg.section.name);
890                break;
891            }
892    }
893   
894    /* write regions */
895    for (size_t i = 0; i < regions.size(); i++)
896    {   
897        const ElfRegionTemplate<Types>& region = regions[i];
898        // fix alignment
899        uint64_t toFill = 0;
900        typename Types::Word ralign = (region.type==ElfRegionType::SECTION) ?
901                        region.section.align : 0;
902        ralign = std::max(region.align, ralign);
903        if (ralign > 1)
904        {
905            const uint64_t curOffset = (fob.getWritten()-startOffset);
906            if (ralign!=0 && (curOffset&(ralign-1))!=0)
907                toFill = ralign - (curOffset&(ralign-1));
908            fob.fill(toFill, 0);
909        }
910        assert(regionOffsets[i] == fob.getWritten()-startOffset);
911       
912        // write content
913        if (region.type == ElfRegionType::PHDR_TABLE)
914        {
915            /* write program headers */
916            for (const auto& progHeader: progHeaders)
917            {
918                typename Types::Phdr phdr;
919                SLEV(phdr.p_type, progHeader.type);
920                SLEV(phdr.p_flags, progHeader.flags);
921                const ElfRegionTemplate<Types> startRegion(sizeof(typename Types::Ehdr),
922                        (const cxbyte*)nullptr, sizeof(typename Types::Word));
923                // get first region of program header and it offset, index and address
924                const ElfRegionTemplate<Types>& sregion = 
925                        (progHeader.regionStart==PHREGION_FILESTART) ? startRegion :
926                        regions[progHeader.regionStart];
927                const cxuint rstart = (progHeader.regionStart!=PHREGION_FILESTART) ?
928                            progHeader.regionStart : 0;
929                const typename Types::Word sroffset =
930                        (progHeader.regionStart!=PHREGION_FILESTART) ?
931                            regionOffsets[progHeader.regionStart] : 0;
932                const typename Types::Word sraddress =
933                        (progHeader.regionStart!=PHREGION_FILESTART) ?
934                            regionAddresses[progHeader.regionStart] : 0;
935               
936                // zero offset, allow to set zero offset of section
937                bool zeroOffset = sregion.type == ElfRegionType::SECTION &&
938                        sregion.section.zeroOffset;
939                SLEV(phdr.p_offset, !zeroOffset ? sroffset : 0);
940                if (progHeader.align==0 && progHeader.regionsNum==0)
941                    SLEV(phdr.p_align, 0);
942                else if (progHeader.align==0)
943                {
944                    typename Types::Word align = (sregion.type==ElfRegionType::SECTION) ?
945                            sregion.section.align : 0;
946                    align = std::max(sregion.align, align);
947                    SLEV(phdr.p_align, align);
948                }
949                else
950                    SLEV(phdr.p_align, progHeader.align);
951               
952                /* paddrBase and vaddrBase is base to program header virtual and physical
953                 * addresses for program header. if not defined then get address base
954                 * from ELF header */
955                if (progHeader.paddrBase == Types::nobase)
956                    SLEV(phdr.p_paddr, sraddress);
957                else if (progHeader.paddrBase != 0)
958                    SLEV(phdr.p_paddr, progHeader.paddrBase + sraddress);
959                else if (header.paddrBase != 0)
960                    SLEV(phdr.p_paddr, header.paddrBase + sraddress);
961                else
962                    SLEV(phdr.p_paddr, 0);
963               
964                // these same rule for vaddrBase
965                if (progHeader.vaddrBase == Types::nobase)
966                    SLEV(phdr.p_vaddr, sraddress);
967                else if (progHeader.vaddrBase != 0)
968                    SLEV(phdr.p_vaddr, progHeader.vaddrBase + sraddress);
969                else if (header.vaddrBase != 0)
970                    SLEV(phdr.p_vaddr, header.vaddrBase + sraddress);
971                else
972                    SLEV(phdr.p_vaddr, 0);
973               
974                // last region size for file - if nobits section then we assume zero size
975                if (progHeader.regionsNum!=0)
976                {
977                    const auto& lastReg = regions[rstart + progHeader.regionsNum-1];
978                    uint64_t fileLastRegSize =(lastReg.type!=ElfRegionType::SECTION ||
979                        lastReg.section.type!=SHT_NOBITS) ? lastReg.size : 0;
980                    /// fileSize - add offset of first region to simulate region alignment
981                    const typename Types::Word fileSize = regionOffsets[rstart+
982                            progHeader.regionsNum-1] + fileLastRegSize - sroffset;
983                    const typename Types::Word phSize = regionAddresses[rstart+
984                            progHeader.regionsNum-1]+regions[rstart+
985                            progHeader.regionsNum-1].size - sraddress;
986                   
987                    if (progHeader.haveMemSize)
988                    {
989                        if (progHeader.memSize != 0)
990                            SLEV(phdr.p_memsz, progHeader.memSize);
991                        else
992                            SLEV(phdr.p_memsz, phSize);
993                    }
994                    else
995                        SLEV(phdr.p_memsz, 0);
996                    SLEV(phdr.p_filesz, fileSize);
997                }
998                else
999                {
1000                    SLEV(phdr.p_memsz, 0);
1001                    SLEV(phdr.p_filesz, 0);
1002                }
1003                fob.writeObject(phdr);
1004            }
1005        }
1006        else if (region.type == ElfRegionType::SHDR_TABLE)
1007        {
1008            /* write section headers table */
1009            if (addNullSection)
1010                fob.fill(sizeof(typename Types::Shdr), 0);
1011            uint32_t nameOffset = (addNullSection);
1012            for (cxuint j = 0; j < regions.size(); j++)
1013            {
1014                const auto& region2 = regions[j];
1015                if (region2.type == ElfRegionType::SECTION)
1016                {
1017                    typename Types::Shdr shdr;
1018                    if (region2.section.name!=nullptr && region2.section.name[0]!=0)
1019                        SLEV(shdr.sh_name, nameOffset);
1020                    else // set empty name offset
1021                        SLEV(shdr.sh_name, nullSectionNameOffset);
1022                    SLEV(shdr.sh_type, region2.section.type);
1023                    SLEV(shdr.sh_flags, region2.section.flags);
1024                    SLEV(shdr.sh_offset, (!region2.section.zeroOffset) ?
1025                                regionOffsets[j] : 0);
1026                    SLEV(shdr.sh_addr, resolveSectionAddress(header, region2,
1027                                     regionAddresses[j]));
1028                   
1029                    if (region2.align != 0 || j+1 >= regions.size() ||
1030                        regionOffsets[j]+region2.size == regionOffsets[j+1])
1031                        SLEV(shdr.sh_size, region2.size);
1032                    else // otherwise if not match this size
1033                        SLEV(shdr.sh_size, regionOffsets[j+1]-regionOffsets[j]);
1034                   
1035                    if ((region2.section.type!=SHT_SYMTAB &&
1036                         region2.section.type!=SHT_DYNSYM) ||
1037                            region2.section.info != BINGEN_DEFAULT)
1038                        // put set info
1039                        SLEV(shdr.sh_info, region2.section.info);
1040                    else // if symbtabs
1041                    {
1042                        // otherwise if default for symtabs, put count of last local
1043                        const auto& symbolsList = (region2.section.type == SHT_SYMTAB) ?
1044                            symbols : dynSymbols;
1045                        cxuint lastLocal = 0;
1046                        for (size_t l = 0; l < symbolsList.size(); l++)
1047                            if (ELF32_ST_BIND(symbolsList[l].info)==STB_LOCAL)
1048                                lastLocal = l+1;
1049                        if ((region2.section.type==SHT_SYMTAB && addNullSym) ||
1050                            (region2.section.type==SHT_DYNSYM && addNullDynSym))
1051                            lastLocal++;
1052                        SLEV(shdr.sh_info, lastLocal);
1053                    }
1054                   
1055                    SLEV(shdr.sh_addralign, (region2.section.align==0) ?
1056                            region2.align : region2.section.align);
1057                    if (region2.section.link == 0)
1058                    {
1059                        // set up link (for symtab is .strtab for .dynsym is dynstr)
1060                        if (::strcmp(region2.section.name, ".symtab") == 0)
1061                            SLEV(shdr.sh_link, strTab);
1062                        else if (::strcmp(region2.section.name, ".dynsym") == 0)
1063                            SLEV(shdr.sh_link, dynStr);
1064                        else // otherwise is value is link (zero)
1065                            SLEV(shdr.sh_link, region2.section.link);
1066                    }
1067                    else
1068                        SLEV(shdr.sh_link, region2.section.link);
1069                   
1070                    // set up entry size for sections
1071                    if (region2.section.type == SHT_SYMTAB ||
1072                        region2.section.type == SHT_DYNSYM)
1073                        SLEV(shdr.sh_entsize, sizeof(typename Types::Sym));
1074                    else if (region2.section.type == SHT_DYNAMIC)
1075                        SLEV(shdr.sh_entsize, sizeof(typename Types::Dyn));
1076                    else // if not default
1077                        SLEV(shdr.sh_entsize, region2.section.entSize);
1078                    if (region2.section.name!=nullptr && region2.section.name[0]!=0)
1079                        nameOffset += ::strlen(region2.section.name)+1;
1080                    fob.writeObject(shdr);
1081                }
1082            }
1083        }
1084        else if (region.type == ElfRegionType::USER)
1085        {
1086            if (region.dataFromPointer)
1087                fob.writeArray(region.size, region.data);
1088            else
1089                (*region.dataGen)(fob);
1090        }
1091        else if (region.type == ElfRegionType::SECTION)
1092        {
1093            if (region.data == nullptr)
1094            {
1095                if (region.section.type == SHT_SYMTAB || region.section.type == SHT_DYNSYM)
1096                {
1097                    uint32_t nameOffset = 0;
1098                    // put null symbol if addNullSym or addNumDynSym is true
1099                    if (region.section.type == SHT_SYMTAB && addNullSym)
1100                    {
1101                        fob.fill(sizeof(typename Types::Sym), 0);
1102                        nameOffset = 1;
1103                    }
1104                    if (region.section.type == SHT_DYNSYM && addNullDynSym)
1105                    {
1106                        fob.fill(sizeof(typename Types::Sym), 0);
1107                        nameOffset = 1;
1108                    }
1109                    const auto& symbolsList = (region.section.type == SHT_SYMTAB) ?
1110                            symbols : dynSymbols;
1111                    for (const auto& inSym: symbolsList)
1112                    {
1113                        typename Types::Sym sym;
1114                        if (inSym.name != nullptr && inSym.name[0] != 0)
1115                            SLEV(sym.st_name, nameOffset);
1116                        else  // set empty name offset (symbol or dynamic symbol)
1117                            SLEV(sym.st_name, (region.section.type == SHT_SYMTAB) ?
1118                                        nullSymNameOffset : nullDynSymNameOffset);
1119                       
1120                        SLEV(sym.st_shndx, inSym.sectionIndex);
1121                        SLEV(sym.st_size, inSym.size);
1122                        /// if value defined as address
1123                        if (!inSym.valueIsAddr)
1124                            SLEV(sym.st_value, inSym.value);
1125                        // if not use conversion to address with section addrBase
1126                        else if ((inSym.sectionIndex != 0 || !addNullSection) &&
1127                                regions[sectionRegions[
1128                                    inSym.sectionIndex]].section.addrBase != 0)
1129                        {
1130                            // store symbol value as address or value
1131                            typename Types::Word addrBase = regions[sectionRegions[
1132                                    inSym.sectionIndex]].section.addrBase;
1133                            SLEV(sym.st_value, inSym.value + regionOffsets[
1134                                    sectionRegions[inSym.sectionIndex]] +
1135                                    (addrBase!=Types::nobase ? addrBase : 0));
1136                        }
1137                        else if (header.vaddrBase!=Types::nobase)
1138                            // use elf headerf virtual address base
1139                            SLEV(sym.st_value, inSym.value + regionOffsets[
1140                                sectionRegions[inSym.sectionIndex]] +
1141                                (header.vaddrBase!=Types::nobase ? header.vaddrBase : 0));
1142                        sym.st_other = inSym.other;
1143                        sym.st_info = inSym.info;
1144                        if (inSym.name != nullptr && inSym.name[0] != 0)
1145                            nameOffset += ::strlen(inSym.name)+1;
1146                        fob.writeObject(sym);
1147                    }
1148                }
1149                else if (region.section.type == SHT_DYNAMIC)
1150                {
1151                    // dynamic table
1152                    typename Types::Dyn dyn;
1153                    for (size_t k = 0; k < dynamics.size(); k++)
1154                    {
1155                        SLEV(dyn.d_tag, dynamics[k]);
1156                        SLEV(dyn.d_un.d_val, dynamicValues[k]);
1157                        fob.writeObject(dyn);
1158                    }
1159                    SLEV(dyn.d_tag, DT_NULL);
1160                    SLEV(dyn.d_un.d_val, 0U);
1161                    fob.writeObject(dyn);
1162                }
1163                else if (region.section.type == SHT_HASH)
1164                {
1165                    // creating hash table and put it
1166                    const std::vector<ElfSymbolTemplate<Types> >& hashSymbols = 
1167                        (isHashDynSym) ? dynSymbols : symbols;
1168                    bool addNullHashSym = (isHashDynSym) ? addNullDynSym : addNullSym;
1169                    Array<uint32_t> hashTable(2 + hashSymbols.size() + addNullHashSym +
1170                                bucketsNum);
1171                    createHashTable(bucketsNum, hashSymbols.size()+addNullHashSym,
1172                                addNullHashSym, hashCodes.get(), hashTable.data());
1173                    fob.writeArray(hashTable.size(), hashTable.data());
1174                }
1175                else if (region.section.type == SHT_NOTE)
1176                {
1177                    // putting ELF notes
1178                    for (const ElfNote& note: notes)
1179                    {
1180                        typename Types::Nhdr nhdr;
1181                        size_t nameSize = ::strlen(note.name)+1;
1182                        size_t descSize = note.descSize;
1183                        SLEV(nhdr.n_namesz, nameSize);
1184                        SLEV(nhdr.n_descsz, descSize);
1185                        SLEV(nhdr.n_type, note.type);
1186                        fob.writeObject(nhdr);
1187                        fob.write(nameSize, note.name);
1188                        if ((nameSize&3) != 0)
1189                            fob.fill(4 - (nameSize&3), 0);
1190                        fob.writeArray(descSize, note.desc);
1191                        if ((descSize&3) != 0)
1192                            fob.fill(4 - (descSize&3), 0);
1193                    }
1194                }
1195                else if (region.section.type == SHT_STRTAB)
1196                {
1197                    // put symbol names and section names
1198                    if (::strcmp(region.section.name, ".strtab") == 0)
1199                    {
1200                        if (addNullSym)
1201                            fob.put(0);
1202                        for (const auto& sym: symbols)
1203                            if (sym.name != nullptr && sym.name[0] != 0)
1204                                fob.write(::strlen(sym.name)+1, sym.name);
1205                    }
1206                    else if (::strcmp(region.section.name, ".dynstr") == 0)
1207                    {
1208                        if (addNullDynSym)
1209                            fob.put(0);
1210                        for (const auto& sym: dynSymbols)
1211                            if (sym.name != nullptr && sym.name[0] != 0)
1212                                fob.write(::strlen(sym.name)+1, sym.name);
1213                    }
1214                    else if (::strcmp(region.section.name, ".shstrtab") == 0)
1215                    {
1216                        if (addNullSection)
1217                            fob.put(0);
1218                        for (const auto& region2: regions)
1219                            if (region2.type == ElfRegionType::SECTION &&
1220                                region2.section.name != nullptr &&
1221                                region2.section.name[0] != 0)
1222                                fob.write(::strlen(region2.section.name)+1,
1223                                          region2.section.name);
1224                    }
1225                }
1226            }
1227            else if (region.section.type != SHT_NOBITS)
1228            {
1229                if (region.dataFromPointer)
1230                    fob.writeArray(region.size, region.data);
1231                else
1232                    (*region.dataGen)(fob);
1233            }
1234        }
1235    }
1236    fob.flush();
1237    fob.getOStream().flush();
1238    assert(size == fob.getWritten()-startOffset);
1239}
1240
1241template class CLRX::ElfBinaryGenTemplate<CLRX::Elf32Types>;
1242template class CLRX::ElfBinaryGenTemplate<CLRX::Elf64Types>;
Note: See TracBrowser for help on using the repository browser.