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

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

CLRadeonExtender: ElfBinaries?: fixes for condition when no null section added.

File size: 40.0 KB
Line 
1/*
2 *  CLRadeonExtender - Unofficial OpenCL Radeon Extensions Library
3 *  Copyright (C) 2014-2016 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 <cstdlib>
22#include <cstring>
23#include <cstdint>
24#include <climits>
25#include <utility>
26#include <string>
27#include <cassert>
28#include <CLRX/amdbin/Elf.h>
29#include <CLRX/utils/Utilities.h>
30#include <CLRX/utils/MemAccess.h>
31#include <CLRX/amdbin/AmdBinaries.h>
32
33static const uint32_t elfMagicValue = 0x464c457fU;
34
35/* INFO: in this file is used ULEV function for conversion
36 * from LittleEndian and unaligned access to other memory access policy and endianness
37 * Please use this function whenever you want to get or set word in ELF binary,
38 * because ELF binaries can be unaligned in memory (as inner binaries).
39 */
40
41using namespace CLRX;
42
43/* determine unfinished strings region in string table for checking further consistency */
44static size_t unfinishedRegionOfStringTable(const cxbyte* table, size_t size)
45{
46    if (size == 0) // if zero
47        return 0;
48    size_t k;
49    for (k = size-1; k>0 && table[k]!=0; k--);
50   
51    return (table[k]==0)?k+1:k;
52}
53
54/* elf32 types */
55
56const cxbyte CLRX::Elf32Types::ELFCLASS = ELFCLASS32;
57const uint32_t CLRX::Elf32Types::bitness = 32;
58const char* CLRX::Elf32Types::bitName = "32";
59
60/* elf64 types */
61
62const cxbyte CLRX::Elf64Types::ELFCLASS = ELFCLASS64;
63const cxuint CLRX::Elf64Types::bitness = 64;
64const char* CLRX::Elf64Types::bitName = "64";
65
66/* ElfBinaryTemplate */
67
68template<typename Types>
69ElfBinaryTemplate<Types>::ElfBinaryTemplate() : binaryCodeSize(0), binaryCode(nullptr),
70        sectionStringTable(nullptr), symbolStringTable(nullptr),
71        symbolTable(nullptr), dynSymStringTable(nullptr), dynSymTable(nullptr),
72        symbolsNum(0), dynSymbolsNum(0),
73        symbolEntSize(0), dynSymEntSize(0)
74{ }
75
76template<typename Types>
77ElfBinaryTemplate<Types>::~ElfBinaryTemplate()
78{ }
79
80template<typename Types>
81ElfBinaryTemplate<Types>::ElfBinaryTemplate(size_t _binaryCodeSize, cxbyte* _binaryCode,
82             Flags _creationFlags) : creationFlags(_creationFlags),
83        binaryCodeSize(_binaryCodeSize), binaryCode(_binaryCode),
84        sectionStringTable(nullptr), symbolStringTable(nullptr),
85        symbolTable(nullptr), dynSymStringTable(nullptr), dynSymTable(nullptr),
86        symbolsNum(0), dynSymbolsNum(0), symbolEntSize(0), dynSymEntSize(0)       
87{
88    if (binaryCodeSize < sizeof(typename Types::Ehdr))
89        throw Exception("Binary is too small!!!");
90   
91    const typename Types::Ehdr* ehdr =
92            reinterpret_cast<const typename Types::Ehdr*>(binaryCode);
93   
94    if (ULEV(*reinterpret_cast<const uint32_t*>(binaryCode)) != elfMagicValue)
95        throw Exception("This is not ELF binary");
96    if (ehdr->e_ident[EI_CLASS] != Types::ELFCLASS)
97        throw Exception(std::string("This is not ")+Types::bitName+"bit ELF binary");
98    if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB)
99        throw Exception("Other than little-endian binaries are not supported!");
100   
101    if ((ULEV(ehdr->e_phoff) == 0 && ULEV(ehdr->e_phnum) != 0))
102        throw Exception("Elf invalid phoff and phnum combination");
103    if (ULEV(ehdr->e_phoff) != 0)
104    {   /* reading and checking program headers */
105        if (ULEV(ehdr->e_phoff) > binaryCodeSize)
106            throw Exception("ProgramHeaders offset out of range!");
107        if (usumGt(ULEV(ehdr->e_phoff),
108                   ((typename Types::Word)ULEV(ehdr->e_phentsize))*ULEV(ehdr->e_phnum),
109                   binaryCodeSize))
110            throw Exception("ProgramHeaders offset+size out of range!");
111       
112        cxuint phnum = ULEV(ehdr->e_phnum);
113        // checking program header segment offset ranges
114        for (cxuint i = 0; i < phnum; i++)
115        {
116            const typename Types::Phdr& phdr = getProgramHeader(i);
117            if (ULEV(phdr.p_offset) > binaryCodeSize)
118                throw Exception("Segment offset out of range!");
119            if (usumGt(ULEV(phdr.p_offset), ULEV(phdr.p_filesz), binaryCodeSize))
120                throw Exception("Segment offset+size out of range!");
121        }
122    }
123   
124    if ((ULEV(ehdr->e_shoff) == 0 && ULEV(ehdr->e_shnum) != 0))
125        throw Exception("Elf invalid shoff and shnum combination");
126    if (ULEV(ehdr->e_shoff) != 0 && ULEV(ehdr->e_shstrndx) != SHN_UNDEF)
127    {   /* indexing of sections */
128        if (ULEV(ehdr->e_shoff) > binaryCodeSize)
129            throw Exception("SectionHeaders offset out of range!");
130        if (usumGt(ULEV(ehdr->e_shoff),
131                  ((typename Types::Word)ULEV(ehdr->e_shentsize))*ULEV(ehdr->e_shnum),
132                  binaryCodeSize))
133            throw Exception("SectionHeaders offset+size out of range!");
134        if (ULEV(ehdr->e_shstrndx) >= ULEV(ehdr->e_shnum))
135            throw Exception("Shstrndx out of range!");
136       
137        typename Types::Shdr& shstrShdr = getSectionHeader(ULEV(ehdr->e_shstrndx));
138        sectionStringTable = binaryCode + ULEV(shstrShdr.sh_offset);
139        const size_t unfinishedShstrPos = unfinishedRegionOfStringTable(
140                    sectionStringTable, ULEV(shstrShdr.sh_size));
141       
142        const typename Types::Shdr* symTableHdr = nullptr;
143        const typename Types::Shdr* dynSymTableHdr = nullptr;
144       
145        cxuint shnum = ULEV(ehdr->e_shnum);
146        if ((creationFlags & ELF_CREATE_SECTIONMAP) != 0)
147            sectionIndexMap.resize(shnum);
148        for (cxuint i = 0; i < shnum; i++)
149        {
150            const typename Types::Shdr& shdr = getSectionHeader(i);
151            /// checking section offset ranges
152            if (ULEV(shdr.sh_offset) > binaryCodeSize)
153                throw Exception("Section offset out of range!");
154            if (ULEV(shdr.sh_type) != SHT_NOBITS)
155                if (usumGt(ULEV(shdr.sh_offset), ULEV(shdr.sh_size), binaryCodeSize))
156                    throw Exception("Section offset+size out of range!");
157            if (ULEV(shdr.sh_link) >= ULEV(ehdr->e_shnum))
158                throw Exception("Section link out of range!");
159           
160            const typename Types::Size sh_nameindx = ULEV(shdr.sh_name);
161            if (sh_nameindx >= ULEV(shstrShdr.sh_size))
162                throw Exception("Section name index out of range!");
163           
164            if (sh_nameindx >= unfinishedShstrPos)
165                throw Exception("Unfinished section name!");
166           
167            const char* shname =
168                reinterpret_cast<const char*>(sectionStringTable + sh_nameindx);
169           
170            if ((creationFlags & ELF_CREATE_SECTIONMAP) != 0)
171                sectionIndexMap[i] = std::make_pair(shname, i);
172            // set symbol table and dynamic symbol table pointers
173            if (ULEV(shdr.sh_type) == SHT_SYMTAB)
174                symTableHdr = &shdr;
175            if (ULEV(shdr.sh_type) == SHT_DYNSYM)
176                dynSymTableHdr = &shdr;
177        }
178        if ((creationFlags & ELF_CREATE_SECTIONMAP) != 0)
179            mapSort(sectionIndexMap.begin(), sectionIndexMap.end(), CStringLess());
180       
181        if (symTableHdr != nullptr)
182        {   // indexing symbols
183            if (ULEV(symTableHdr->sh_entsize) < sizeof(typename Types::Sym))
184                throw Exception("SymTable entry size is too small!");
185           
186            symbolEntSize = ULEV(symTableHdr->sh_entsize);
187            symbolTable = binaryCode + ULEV(symTableHdr->sh_offset);
188            if (ULEV(symTableHdr->sh_link) == SHN_UNDEF)
189                throw Exception("Symbol table doesn't have string table");
190           
191            typename Types::Shdr& symstrShdr = getSectionHeader(ULEV(symTableHdr->sh_link));
192            symbolStringTable = binaryCode + ULEV(symstrShdr.sh_offset);
193           
194            const size_t unfinishedSymstrPos = unfinishedRegionOfStringTable(
195                    symbolStringTable, ULEV(symstrShdr.sh_size));
196            symbolsNum = ULEV(symTableHdr->sh_size)/ULEV(symTableHdr->sh_entsize);
197            if ((creationFlags & ELF_CREATE_SYMBOLMAP) != 0)
198                symbolIndexMap.resize(symbolsNum);
199           
200            for (typename Types::Size i = 0; i < symbolsNum; i++)
201            {   /* verify symbol names */
202                const typename Types::Sym& sym = getSymbol(i);
203                const typename Types::Size symnameindx = ULEV(sym.st_name);
204                if (symnameindx >= ULEV(symstrShdr.sh_size))
205                    throw Exception("Symbol name index out of range!");
206                // check whether name is finished in string section content
207                if (symnameindx >= unfinishedSymstrPos)
208                    throw Exception("Unfinished symbol name!");
209               
210                const char* symname =
211                    reinterpret_cast<const char*>(symbolStringTable + symnameindx);
212                // add to symbol map
213                if ((creationFlags & ELF_CREATE_SYMBOLMAP) != 0)
214                    symbolIndexMap[i] = std::make_pair(symname, i);
215            }
216            if ((creationFlags & ELF_CREATE_SYMBOLMAP) != 0)
217                mapSort(symbolIndexMap.begin(), symbolIndexMap.end(), CStringLess());
218        }
219        if (dynSymTableHdr != nullptr)
220        {   // indexing dynamic symbols
221            if (ULEV(dynSymTableHdr->sh_entsize) < sizeof(typename Types::Sym))
222                throw Exception("DynSymTable entry size is too small!");
223           
224            dynSymEntSize = ULEV(dynSymTableHdr->sh_entsize);
225            dynSymTable = binaryCode + ULEV(dynSymTableHdr->sh_offset);
226            if (ULEV(dynSymTableHdr->sh_link) == SHN_UNDEF)
227                throw Exception("DynSymbol table doesn't have string table");
228           
229            typename Types::Shdr& dynSymstrShdr =
230                    getSectionHeader(ULEV(dynSymTableHdr->sh_link));
231            dynSymbolsNum = ULEV(dynSymTableHdr->sh_size)/ULEV(dynSymTableHdr->sh_entsize);
232           
233            dynSymStringTable = binaryCode + ULEV(dynSymstrShdr.sh_offset);
234            const size_t unfinishedSymstrPos = unfinishedRegionOfStringTable(
235                    dynSymStringTable, ULEV(dynSymstrShdr.sh_size));
236           
237            if ((creationFlags & ELF_CREATE_DYNSYMMAP) != 0)
238                dynSymIndexMap.resize(dynSymbolsNum);
239           
240            for (typename Types::Size i = 0; i < dynSymbolsNum; i++)
241            {   /* verify symbol names */
242                const typename Types::Sym& sym = getDynSymbol(i);
243                const typename Types::Size symnameindx = ULEV(sym.st_name);
244                if (symnameindx >= ULEV(dynSymstrShdr.sh_size))
245                    throw Exception("DynSymbol name index out of range!");
246                // check whether name is finished in string section content
247                if (symnameindx >= unfinishedSymstrPos)
248                    throw Exception("Unfinished dynsymbol name!");
249               
250                const char* symname =
251                    reinterpret_cast<const char*>(dynSymStringTable + symnameindx);
252                // add to symbol map
253                if ((creationFlags & ELF_CREATE_DYNSYMMAP) != 0)
254                    dynSymIndexMap[i] = std::make_pair(symname, i);
255            }
256            if ((creationFlags & ELF_CREATE_DYNSYMMAP) != 0)
257                mapSort(dynSymIndexMap.begin(), dynSymIndexMap.end(), CStringLess());
258        }
259    }
260}
261
262template<typename Types>
263uint16_t ElfBinaryTemplate<Types>::getSectionIndex(const char* name) const
264{
265    if (hasSectionMap())
266    {
267        SectionIndexMap::const_iterator it = binaryMapFind(
268                    sectionIndexMap.begin(), sectionIndexMap.end(), name, CStringLess());
269        if (it == sectionIndexMap.end())
270            throw Exception(std::string("Can't find Elf")+Types::bitName+" Section");
271        return it->second;
272    }
273    else
274    {
275        for (cxuint i = 0; i < getSectionHeadersNum(); i++)
276        {
277            if (::strcmp(getSectionName(i), name) == 0)
278                return i;
279        }
280        throw Exception(std::string("Can't find Elf")+Types::bitName+" Section");
281    }
282}
283
284template<typename Types>
285typename Types::Size ElfBinaryTemplate<Types>::getSymbolIndex(const char* name) const
286{
287    SymbolIndexMap::const_iterator it = binaryMapFind(
288                    symbolIndexMap.begin(), symbolIndexMap.end(), name, CStringLess());
289    if (it == symbolIndexMap.end())
290        throw Exception(std::string("Can't find Elf")+Types::bitName+" Symbol");
291    return it->second;
292}
293
294template<typename Types>
295typename Types::Size ElfBinaryTemplate<Types>::getDynSymbolIndex(const char* name) const
296{
297    SymbolIndexMap::const_iterator it = binaryMapFind(
298                    dynSymIndexMap.begin(), dynSymIndexMap.end(), name, CStringLess());
299    if (it == dynSymIndexMap.end())
300        throw Exception(std::string("Can't find Elf")+Types::bitName+" DynSymbol");
301    return it->second;
302}
303
304template class CLRX::ElfBinaryTemplate<CLRX::Elf32Types>;
305template class CLRX::ElfBinaryTemplate<CLRX::Elf64Types>;
306
307bool CLRX::isElfBinary(size_t binarySize, const cxbyte* binary)
308{
309    if (binarySize < sizeof(Elf32_Ehdr) ||
310        ULEV(*reinterpret_cast<const uint32_t*>(binary)) != elfMagicValue)
311        return false;
312    if ((binary[EI_CLASS] != ELFCLASS32 && binary[EI_CLASS] != ELFCLASS64) ||
313        binary[EI_DATA] != ELFDATA2LSB) // only LSB elf is supported
314        return false;
315    if ((binary[EI_CLASS] == ELFCLASS32 && binarySize < sizeof(Elf32_Ehdr)) ||
316        (binary[EI_CLASS] == ELFCLASS64 && binarySize < sizeof(Elf64_Ehdr)))
317        return false;
318    if (ULEV(*((const uint64_t*)(binary+8))) != 0)
319        return false;
320    return true;
321}
322
323/*
324 * Elf binary generator
325 */
326
327uint16_t CLRX::convertSectionId(cxuint sectionIndex, const uint16_t* builtinSections,
328                  cxuint maxBuiltinSection, cxuint extraSectionIndex)
329{
330    if (sectionIndex == ELFSECTID_NULL)
331        return 0;
332    if (sectionIndex == ELFSECTID_ABS)
333        return SHN_ABS;
334    if (sectionIndex == ELFSECTID_UNDEF)
335        return SHN_UNDEF;
336    if (sectionIndex < ELFSECTID_START)
337        return sectionIndex+extraSectionIndex;
338    else if (sectionIndex >= ELFSECTID_START && sectionIndex <= maxBuiltinSection)
339    {
340        const uint16_t shndx = builtinSections[sectionIndex-ELFSECTID_START];
341        if (shndx == SHN_UNDEF) // if table entry for sectionIndex is not defined
342            throw Exception("Wrong BinSection:sectionId");
343        return builtinSections[sectionIndex-ELFSECTID_START];
344    }
345    else // failed
346        throw Exception("Wrong BinSection:sectionId");
347}
348
349ElfRegionContent::~ElfRegionContent()
350{ }
351
352template<typename Types>
353static std::unique_ptr<uint32_t[]> calculateHashValuesForSymbols(bool addNullSymbol,
354            const std::vector<ElfSymbolTemplate<Types> >& symbols)
355{
356    const size_t symsNum = symbols.size() + addNullSymbol;
357    std::unique_ptr<uint32_t[]> hashCodes(new uint32_t[symsNum]);
358    if (addNullSymbol)
359        hashCodes[0] = 0;
360    for (size_t i = 0; i < symbols.size(); i++)
361    {
362        uint32_t h = 0, g;
363        const cxbyte* name = reinterpret_cast<const cxbyte*>(symbols[i].name);
364        while(*name!=0)
365        {
366            h = (h<<4) + *name++;
367            g = h & 0xf0000000U;
368            if (g) h ^= g>>24;
369            h &= ~g;
370        }
371        hashCodes[i+addNullSymbol] = h;
372    }
373    return hashCodes;
374}
375
376/// return bucket number
377static uint32_t optimizeHashBucketsNum(uint32_t hashNum, bool skipFirst,
378                           const uint32_t* hashCodes)
379{
380    uint32_t bestBucketNum = 0;
381    uint64_t bestValue = UINT64_MAX;
382    uint32_t firstStep = std::max(uint32_t(hashNum>>2), 1U);
383    uint64_t maxSteps = (uint64_t(hashNum)<<1) - (firstStep) + 1;
384    const uint32_t steps = (maxSteps<=1000U) ? hashNum : hashNum<<((32-CLZ32(hashNum))>>1);
385   
386    std::unique_ptr<uint32_t[]> chainLengths(new uint32_t[(hashNum<<2)+1]);
387    const uint32_t stepSize = maxSteps / steps;
388    for (uint32_t buckets = firstStep; buckets <= (hashNum<<1); buckets += stepSize)
389    {   //
390        std::fill(chainLengths.get(), chainLengths.get() + buckets, 0U);
391        // calculate chain lengths
392        for (size_t i = skipFirst; i < hashNum; i++)
393            chainLengths[hashCodes[i] % buckets]++;
394        /// value, smaller is better
395        uint64_t value = uint64_t(buckets);
396        for (uint32_t i = 0; i < buckets; i++)
397            value += chainLengths[i]*chainLengths[i];
398        if (value < bestValue)
399        {
400            bestBucketNum = buckets;
401            bestValue = value;
402        }
403    }
404    return bestBucketNum;
405}
406
407template<typename Types>
408ElfBinaryGenTemplate<Types>::ElfBinaryGenTemplate()
409        : sizeComputed(false), addNullSym(true), addNullDynSym(true), addNullSection(true),
410          addrStartRegion(0), shStrTab(0), strTab(0), dynStr(0), shdrTabRegion(0),
411          phdrTabRegion(0), bucketsNum(0)
412{ }
413
414template<typename Types>
415ElfBinaryGenTemplate<Types>::ElfBinaryGenTemplate(const ElfHeaderTemplate<Types>& _header,
416            bool _addNullSym, bool _addNullDynSym, bool _addNullSection,
417            cxuint addrCountingFromRegion)
418        : sizeComputed(false), addNullSym(_addNullSym), addNullDynSym(_addNullDynSym),
419          addNullSection(_addNullSection),  addrStartRegion(addrCountingFromRegion),
420          shStrTab(0), strTab(0), dynStr(0), shdrTabRegion(0), phdrTabRegion(0),
421          header(_header), bucketsNum(0)
422{ }
423
424template<typename Types>
425void ElfBinaryGenTemplate<Types>::addRegion(const ElfRegionTemplate<Types>& region)
426{ regions.push_back(region); }
427
428template<typename Types>
429void ElfBinaryGenTemplate<Types>::addProgramHeader(
430            const ElfProgramHeaderTemplate<Types>& progHeader)
431{ progHeaders.push_back(progHeader); }
432
433template<typename Types>
434void ElfBinaryGenTemplate<Types>::computeSize()
435{
436    if (sizeComputed) return;
437   
438    /* verify data */
439    if (header.entryRegion != UINT_MAX && header.entryRegion >= regions.size())
440        throw Exception("Header entry region out of range");
441   
442    regionOffsets.reset(new typename Types::Word[regions.size()]);
443    regionAddresses.reset(new typename Types::Word[regions.size()]);
444    size = sizeof(typename Types::Ehdr);
445    sectionsNum = addNullSection; // if add null section
446    for (const auto& region: regions)
447        if (region.type == ElfRegionType::SECTION)
448            sectionsNum++;
449   
450    sectionRegions.reset(new cxuint[sectionsNum+1]);
451    sectionRegions[0] = UINT_MAX;
452    cxuint sectionCount = addNullSection;
453    typename Types::Word address = 0;
454   
455    for (const auto& sym: symbols)
456        if (sym.sectionIndex >= sectionsNum)
457            throw Exception("Symbol section index out of range");
458    for (const auto& sym: dynSymbols)
459        if (sym.sectionIndex >= sectionsNum)
460            throw Exception("DynSymbol section index out of range");
461   
462    for (size_t i = 0; i < regions.size(); i++)
463    {
464        ElfRegionTemplate<Types>& region = regions[i];
465        if (region.align > 1)
466        {   // fix alignment
467            if ((size&(region.align-1))!=0)
468                size += region.align - (size&(region.align-1));
469            if ((address&(region.align-1))!=0)
470                address += region.align - (address&(region.align-1));
471        }
472       
473        regionOffsets[i] = size;
474        regionAddresses[i] = address;
475        // add region size
476        if (region.type == ElfRegionType::PHDR_TABLE)
477        {
478            size += uint64_t(progHeaders.size())*sizeof(typename Types::Phdr);
479            region.size = size-regionOffsets[i];
480            phdrTabRegion = i;
481            for (const auto& progHdr: progHeaders)
482            {
483                if (progHdr.regionStart >= regions.size())
484                    throw Exception("Region start out of range");
485                if (uint64_t(progHdr.regionStart) + progHdr.regionsNum > regions.size())
486                    throw Exception("Region end out of range");
487            }
488        }
489        else if (region.type == ElfRegionType::SHDR_TABLE)
490        {
491            size += uint64_t(sectionsNum)*sizeof(typename Types::Shdr);
492            region.size = size-regionOffsets[i];
493            shdrTabRegion = i;
494        }
495        else if (region.type == ElfRegionType::USER)
496            size += region.size;
497        else if (region.type == ElfRegionType::SECTION)
498        {   // if section
499            if (region.section.link >= sectionsNum)
500                throw Exception("Section link out of range");
501           
502            if (region.section.type != SHT_NOBITS && region.size != 0)
503                size += region.size;
504            else // otherwise get default size for symtab, dynsym, strtab, dynstr
505            {
506                if (region.section.type == SHT_SYMTAB)
507                    size += uint64_t(symbols.size()+addNullSym)*
508                                sizeof(typename Types::Sym);
509                else if (region.section.type == SHT_DYNSYM)
510                    size += uint64_t(dynSymbols.size()+addNullDynSym)*
511                                sizeof(typename Types::Sym);
512                else if (region.section.type == SHT_HASH)
513                {
514                    //calculateHashValuesForSymbols<>()
515                }
516                else if (region.section.type == SHT_STRTAB)
517                {
518                    if (::strcmp(region.section.name, ".strtab") == 0)
519                    {
520                        size += (addNullSym);
521                        for (const auto& sym: symbols)
522                            if (sym.name != nullptr && sym.name[0] != 0)
523                                size += ::strlen(sym.name)+1;
524                    }
525                    else if (::strcmp(region.section.name, ".dynstr") == 0)
526                    {
527                        size += (addNullDynSym);
528                        for (const auto& sym: dynSymbols)
529                            if (sym.name != nullptr && sym.name[0] != 0)
530                                size += ::strlen(sym.name)+1;
531                    }
532                    else if (::strcmp(region.section.name, ".shstrtab") == 0)
533                    {
534                        size += (addNullSection);
535                        for (const auto& region2: regions)
536                        {
537                            if (region2.type == ElfRegionType::SECTION &&
538                                region2.section.name != nullptr &&
539                                region2.section.name[0] != 0)
540                                size += ::strlen(region2.section.name)+1;
541                        }
542                    }
543                }
544                if (region.section.type != SHT_NOBITS)
545                    region.size = size-regionOffsets[i];
546            }
547            if (i >= addrStartRegion) // begin counting address from that region
548                address += region.size;
549           
550            if (::strcmp(region.section.name, ".strtab") == 0)
551                strTab = sectionCount;
552            else if (::strcmp(region.section.name, ".dynstr") == 0)
553                dynStr = sectionCount;
554            else if (::strcmp(region.section.name, ".shstrtab") == 0)
555                shStrTab = sectionCount;
556            sectionRegions[sectionCount] = i;
557            sectionCount++;
558        }
559    }
560   
561    sizeComputed = true;
562}
563
564template<typename Types>
565uint64_t ElfBinaryGenTemplate<Types>::countSize()
566{
567    computeSize();
568    return size;
569}
570
571static void createHashTable(uint32_t bucketsNum, uint32_t hashNum, bool skipFirst,
572                           const uint32_t* hashCodes, uint32_t* output)
573{
574    SULEV(output[0], bucketsNum);
575    SULEV(output[1], hashNum);
576    uint32_t* buckets = output + 2;
577    uint32_t* chains = output + bucketsNum + 2;
578    std::fill(buckets, buckets + bucketsNum, 0U);
579    std::fill(chains, chains + hashNum, STN_UNDEF);
580   
581    std::unique_ptr<uint32_t[]> lastNodes(new uint32_t[bucketsNum]);
582    std::fill(lastNodes.get(), lastNodes.get() + bucketsNum, UINT32_MAX);
583    for (uint32_t i = skipFirst; i < hashNum; i++)
584    {
585        const uint32_t bucket = hashCodes[i] % bucketsNum;
586        if (lastNodes[bucket] == UINT32_MAX)
587        {   // first entry of chain
588            SULEV(buckets[bucket], i);
589            lastNodes[bucket] = i;
590        }
591        else
592        {
593            SULEV(chains[lastNodes[bucket]], i);
594            lastNodes[bucket] = i;
595        }
596    }
597}
598
599template<typename Types>
600void ElfBinaryGenTemplate<Types>::generate(FastOutputBuffer& fob)
601{
602    computeSize();
603    const uint64_t startOffset = fob.getWritten();
604    /* write elf header */
605    {
606        typename Types::Ehdr ehdr;
607        ::memset(ehdr.e_ident, 0, EI_NIDENT);
608        ehdr.e_ident[0] = 0x7f;
609        ehdr.e_ident[1] = 'E';
610        ehdr.e_ident[2] = 'L';
611        ehdr.e_ident[3] = 'F';
612        ehdr.e_ident[4] = Types::ELFCLASS;
613        ehdr.e_ident[5] = ELFDATA2LSB;
614        ehdr.e_ident[6] = EV_CURRENT;
615        ehdr.e_ident[EI_OSABI] = header.osABI;
616        ehdr.e_ident[EI_ABIVERSION] = header.abiVersion;
617        SLEV(ehdr.e_type, header.type);
618        SLEV(ehdr.e_machine, header.machine);
619        SLEV(ehdr.e_version, header.version);
620        SLEV(ehdr.e_flags, header.flags);
621        if (header.entryRegion != UINT_MAX)
622        {   // if have entry
623            typename Types::Word entry = regionOffsets[header.entryRegion] + header.entry;
624            if (regions[header.entryRegion].type == ElfRegionType::SECTION &&
625                regions[header.entryRegion].section.addrBase != 0)
626                entry += regions[header.entryRegion].section.addrBase;
627            else
628                entry += header.vaddrBase;
629           
630            SLEV(ehdr.e_entry, entry);
631        }
632        else
633            SLEV(ehdr.e_entry, 0);
634        SLEV(ehdr.e_ehsize, sizeof(typename Types::Ehdr));
635        if (!progHeaders.empty())
636        {
637            SLEV(ehdr.e_phentsize, sizeof(typename Types::Phdr));
638            SLEV(ehdr.e_phoff, regionOffsets[phdrTabRegion]);
639        }
640        else
641        {
642            SLEV(ehdr.e_phentsize, 0);
643            SLEV(ehdr.e_phoff, 0);
644        }
645        SLEV(ehdr.e_phnum, progHeaders.size());
646        SLEV(ehdr.e_shentsize, sizeof(typename Types::Shdr));
647        SLEV(ehdr.e_shnum, sectionsNum);
648        SLEV(ehdr.e_shoff, regionOffsets[shdrTabRegion]);
649        SLEV(ehdr.e_shstrndx, shStrTab);
650       
651        fob.writeObject(ehdr);
652    }
653   
654    size_t nullSymNameOffset = 0;
655    // if addNullSym is not set, then no empty symbol name added, then we
656    // find first null character
657    if (!addNullSym && !symbols.empty())
658        nullSymNameOffset = ::strlen(symbols[0].name);
659    size_t nullDynSymNameOffset = 0;
660    // if addNullDynSym is not set, then no empty dynamic symbol name added, then we
661    // find first null character
662    if (!addNullDynSym && !dynSymbols.empty())
663        nullDynSymNameOffset = ::strlen(dynSymbols[0].name);
664    // if addNullSection is not set, then no empty section name added, then we
665    // find first null character
666    size_t nullSectionNameOffset = 0;
667    if (!addNullSection)
668    {
669        for (const ElfRegionTemplate<Types>& reg: regions)
670            if (reg.type == ElfRegionType::SECTION)
671            {
672                nullSectionNameOffset = ::strlen(reg.section.name);
673                break;
674            }
675    }
676   
677    /* write regions */
678    for (size_t i = 0; i < regions.size(); i++)
679    {   
680        const ElfRegionTemplate<Types>& region = regions[i];
681        // fix alignment
682        uint64_t toFill = 0;
683        typename Types::Word ralign = (region.type==ElfRegionType::SECTION) ?
684                        region.section.align : 0;
685        ralign = std::max(region.align, ralign);
686        if (ralign > 1)
687        {
688            const uint64_t curOffset = (fob.getWritten()-startOffset);
689            if (ralign!=0 && (curOffset&(ralign-1))!=0)
690                toFill = ralign - (curOffset&(ralign-1));
691            fob.fill(toFill, 0);
692        }
693        assert(regionOffsets[i] == fob.getWritten()-startOffset);
694       
695        // write content
696        if (region.type == ElfRegionType::PHDR_TABLE)
697        {   /* write program headers */
698            for (const auto& progHeader: progHeaders)
699            {
700                typename Types::Phdr phdr;
701                SLEV(phdr.p_type, progHeader.type);
702                SLEV(phdr.p_flags, progHeader.flags);
703                const ElfRegionTemplate<Types>& sregion = regions[progHeader.regionStart];
704                bool zeroOffset = sregion.type == ElfRegionType::SECTION &&
705                        sregion.section.zeroOffset;
706                SLEV(phdr.p_offset, !zeroOffset ?
707                        regionOffsets[progHeader.regionStart] : 0);
708                typename Types::Word align = (sregion.type==ElfRegionType::SECTION) ?
709                        sregion.section.align : 0;
710                align = std::max(sregion.align, align);
711                SLEV(phdr.p_align, align);
712               
713                /* paddrBase and vaddrBase is base to program header virtual and physical
714                 * addresses for program header. if not defined then get address base
715                 * from ELF header */
716                if (progHeader.paddrBase == Types::nobase)
717                    SLEV(phdr.p_paddr, regionAddresses[progHeader.regionStart]);
718                else if (progHeader.paddrBase != 0)
719                    SLEV(phdr.p_paddr, progHeader.paddrBase +
720                                regionAddresses[progHeader.regionStart]);
721                else if (header.paddrBase != 0)
722                    SLEV(phdr.p_paddr, header.paddrBase +
723                                regionAddresses[progHeader.regionStart]);
724                else
725                    SLEV(phdr.p_paddr, 0);
726               
727                if (progHeader.vaddrBase == Types::nobase)
728                    SLEV(phdr.p_vaddr, regionAddresses[progHeader.regionStart]);
729                else if (progHeader.vaddrBase != 0)
730                    SLEV(phdr.p_vaddr, progHeader.vaddrBase +
731                                regionAddresses[progHeader.regionStart]);
732                else if (header.vaddrBase != 0)
733                    SLEV(phdr.p_vaddr, header.vaddrBase +
734                                regionAddresses[progHeader.regionStart]);
735                else
736                    SLEV(phdr.p_vaddr, 0);
737               
738                // last region size for file - if nobits section then we assume zero size
739                const auto& lastReg = regions[progHeader.regionStart+
740                            progHeader.regionsNum-1];
741                uint64_t fileLastRegSize =(lastReg.type!=ElfRegionType::SECTION ||
742                    lastReg.section.type!=SHT_NOBITS) ? lastReg.size : 0;
743                /// fileSize - add offset of first region to simulate region alignment
744                const typename Types::Word fileSize = regionOffsets[progHeader.regionStart+
745                        progHeader.regionsNum-1] + fileLastRegSize -
746                        regionOffsets[progHeader.regionStart];
747                const typename Types::Word phSize = regionAddresses[progHeader.regionStart+
748                        progHeader.regionsNum-1]+regions[progHeader.regionStart+
749                        progHeader.regionsNum-1].size -
750                        regionAddresses[progHeader.regionStart];
751                SLEV(phdr.p_filesz, phSize);
752               
753                if (progHeader.haveMemSize)
754                {
755                    if (progHeader.memSize != 0)
756                        SLEV(phdr.p_memsz, progHeader.memSize);
757                    else
758                        SLEV(phdr.p_memsz, phSize);
759                }
760                else
761                    SLEV(phdr.p_memsz, 0);
762                SLEV(phdr.p_filesz, fileSize);
763                fob.writeObject(phdr);
764            }
765        }
766        else if (region.type == ElfRegionType::SHDR_TABLE)
767        {   /* write section headers table */
768            if (addNullSection)
769                fob.fill(sizeof(typename Types::Shdr), 0);
770            uint32_t nameOffset = (addNullSection);
771            for (cxuint j = 0; j < regions.size(); j++)
772            {
773                const auto& region2 = regions[j];
774                if (region2.type == ElfRegionType::SECTION)
775                {
776                    typename Types::Shdr shdr;
777                    if (region2.section.name!=nullptr && region2.section.name[0]!=0)
778                        SLEV(shdr.sh_name, nameOffset);
779                    else // set empty name offset
780                        SLEV(shdr.sh_name, nullSectionNameOffset);
781                    SLEV(shdr.sh_type, region2.section.type);
782                    SLEV(shdr.sh_flags, region2.section.flags);
783                    SLEV(shdr.sh_offset, (!region2.section.zeroOffset) ?
784                                regionOffsets[j] : 0);
785                    /* addrBase is base address of first section. if not defined
786                     * use address base as virtual address base from elf header */
787                    if (region2.section.addrBase==Types::nobase)
788                        SLEV(shdr.sh_addr, regionAddresses[j]);
789                    else if (region2.section.addrBase != 0)
790                        SLEV(shdr.sh_addr, region2.section.addrBase+regionAddresses[j]);
791                    else if (header.vaddrBase != 0)
792                        SLEV(shdr.sh_addr, header.vaddrBase+regionAddresses[j]);
793                    else
794                        SLEV(shdr.sh_addr, 0);
795                   
796                    if (region2.align != 0 || j+1 >= regions.size() ||
797                        regionOffsets[j]+region2.size == regionOffsets[j+1])
798                        SLEV(shdr.sh_size, region2.size);
799                    else
800                        SLEV(shdr.sh_size, regionOffsets[j+1]-regionOffsets[j]);
801                    SLEV(shdr.sh_info, region2.section.info);
802                    SLEV(shdr.sh_addralign, region2.align);
803                    if (region2.section.link == 0)
804                    {
805                        if (::strcmp(region2.section.name, ".symtab") == 0)
806                            SLEV(shdr.sh_link, strTab);
807                        else if (::strcmp(region2.section.name, ".dynsym") == 0)
808                            SLEV(shdr.sh_link, dynStr);
809                        else
810                            SLEV(shdr.sh_link, region2.section.link);
811                    }
812                    else
813                        SLEV(shdr.sh_link, region2.section.link);
814                   
815                    if (region2.section.type == SHT_SYMTAB ||
816                        region2.section.type == SHT_DYNSYM)
817                        SLEV(shdr.sh_entsize, sizeof(typename Types::Sym));
818                    else
819                        SLEV(shdr.sh_entsize, region2.section.entSize);
820                    if (region2.section.name!=nullptr && region2.section.name[0]!=0)
821                        nameOffset += ::strlen(region2.section.name)+1;
822                    fob.writeObject(shdr);
823                }
824            }
825        }
826        else if (region.type == ElfRegionType::USER)
827        {
828            if (region.dataFromPointer)
829                fob.writeArray(region.size, region.data);
830            else
831                (*region.dataGen)(fob);
832        }
833        else if (region.type == ElfRegionType::SECTION)
834        {
835            if (region.data == nullptr)
836            {
837                if (region.section.type == SHT_SYMTAB || region.section.type == SHT_DYNSYM)
838                {
839                    uint32_t nameOffset = 0;
840                    if (region.section.type == SHT_SYMTAB && addNullSym)
841                    {
842                        fob.fill(sizeof(typename Types::Sym), 0);
843                        nameOffset = 1;
844                    }
845                    if (region.section.type == SHT_DYNSYM && addNullDynSym)
846                    {
847                        fob.fill(sizeof(typename Types::Sym), 0);
848                        nameOffset = 1;
849                    }
850                    const auto& symbolsList = (region.section.type == SHT_SYMTAB) ?
851                            symbols : dynSymbols;
852                    for (const auto& inSym: symbolsList)
853                    {
854                        typename Types::Sym sym;
855                        if (inSym.name != nullptr && inSym.name[0] != 0)
856                            SLEV(sym.st_name, nameOffset);
857                        else  // set empty name offset (symbol or dynamic symbol)
858                            SLEV(sym.st_name, (region.section.type == SHT_SYMTAB) ?
859                                        nullSymNameOffset : nullDynSymNameOffset);
860                       
861                        SLEV(sym.st_shndx, inSym.sectionIndex);
862                        SLEV(sym.st_size, inSym.size);
863                        /// if value defined as address
864                        if (!inSym.valueIsAddr)
865                            SLEV(sym.st_value, inSym.value);
866                        // if not use conversion to address with section addrBase
867                        else if ((inSym.sectionIndex != 0 || !addNullSection) &&
868                                regions[sectionRegions[
869                                    inSym.sectionIndex]].section.addrBase != 0)
870                            SLEV(sym.st_value, inSym.value + regionOffsets[
871                                    sectionRegions[inSym.sectionIndex]] +
872                                    regions[sectionRegions[inSym.sectionIndex]].
873                                            section.addrBase);
874                        else // use elf headerf virtual address base
875                            SLEV(sym.st_value, inSym.value + regionOffsets[
876                                sectionRegions[inSym.sectionIndex]] + header.vaddrBase);
877                        sym.st_other = inSym.other;
878                        sym.st_info = inSym.info;
879                        if (inSym.name != nullptr && inSym.name[0] != 0)
880                            nameOffset += ::strlen(inSym.name)+1;
881                        fob.writeObject(sym);
882                    }
883                }
884                else if (region.section.type == SHT_HASH)
885                {
886                    if (::strcmp(region.section.name, ".hash") != 0)
887                        continue;
888                }
889                else if (region.section.type == SHT_STRTAB)
890                {
891                    if (::strcmp(region.section.name, ".strtab") == 0)
892                    {
893                        if (addNullSym)
894                            fob.put(0);
895                        for (const auto& sym: symbols)
896                            if (sym.name != nullptr && sym.name[0] != 0)
897                                fob.write(::strlen(sym.name)+1, sym.name);
898                    }
899                    else if (::strcmp(region.section.name, ".dynstr") == 0)
900                    {
901                        if (addNullDynSym)
902                            fob.put(0);
903                        for (const auto& sym: dynSymbols)
904                            if (sym.name != nullptr && sym.name[0] != 0)
905                                fob.write(::strlen(sym.name)+1, sym.name);
906                    }
907                    else if (::strcmp(region.section.name, ".shstrtab") == 0)
908                    {
909                        if (addNullSection)
910                            fob.put(0);
911                        for (const auto& region2: regions)
912                            if (region2.type == ElfRegionType::SECTION &&
913                                region2.section.name != nullptr &&
914                                region2.section.name[0] != 0)
915                                fob.write(::strlen(region2.section.name)+1,
916                                          region2.section.name);
917                    }
918                }
919            }
920            else if (region.section.type != SHT_NOBITS)
921            {
922                if (region.dataFromPointer)
923                    fob.writeArray(region.size, region.data);
924                else
925                    (*region.dataGen)(fob);
926            }
927        }
928    }
929    fob.flush();
930    fob.getOStream().flush();
931    assert(size == fob.getWritten()-startOffset);
932}
933
934template class CLRX::ElfBinaryGenTemplate<CLRX::Elf32Types>;
935template class CLRX::ElfBinaryGenTemplate<CLRX::Elf64Types>;
Note: See TracBrowser for help on using the repository browser.