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

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

CLRadeonExtender: Update ElfBinaries?.

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 = 1;
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                    sectionRegions.
515                    calculateHashValuesForSymbols<>()
516                }
517                else if (region.section.type == SHT_STRTAB)
518                {
519                    if (::strcmp(region.section.name, ".strtab") == 0)
520                    {
521                        size += (addNullSym);
522                        for (const auto& sym: symbols)
523                            if (sym.name != nullptr && sym.name[0] != 0)
524                                size += ::strlen(sym.name)+1;
525                    }
526                    else if (::strcmp(region.section.name, ".dynstr") == 0)
527                    {
528                        size += (addNullDynSym);
529                        for (const auto& sym: dynSymbols)
530                            if (sym.name != nullptr && sym.name[0] != 0)
531                                size += ::strlen(sym.name)+1;
532                    }
533                    else if (::strcmp(region.section.name, ".shstrtab") == 0)
534                    {
535                        size += (addNullSection);
536                        for (const auto& region2: regions)
537                        {
538                            if (region2.type == ElfRegionType::SECTION &&
539                                region2.section.name != nullptr &&
540                                region2.section.name[0] != 0)
541                                size += ::strlen(region2.section.name)+1;
542                        }
543                    }
544                }
545                if (region.section.type != SHT_NOBITS)
546                    region.size = size-regionOffsets[i];
547            }
548            if (i >= addrStartRegion) // begin counting address from that region
549                address += region.size;
550           
551            if (::strcmp(region.section.name, ".strtab") == 0)
552                strTab = sectionCount;
553            else if (::strcmp(region.section.name, ".dynstr") == 0)
554                dynStr = sectionCount;
555            else if (::strcmp(region.section.name, ".shstrtab") == 0)
556                shStrTab = sectionCount;
557            sectionRegions[sectionCount] = i;
558            sectionCount++;
559        }
560    }
561   
562    sizeComputed = true;
563}
564
565template<typename Types>
566uint64_t ElfBinaryGenTemplate<Types>::countSize()
567{
568    computeSize();
569    return size;
570}
571
572static void createHashTable(uint32_t bucketsNum, uint32_t hashNum, bool skipFirst,
573                           const uint32_t* hashCodes, uint32_t* output)
574{
575    SULEV(output[0], bucketsNum);
576    SULEV(output[1], hashNum);
577    uint32_t* buckets = output + 2;
578    uint32_t* chains = output + bucketsNum + 2;
579    std::fill(buckets, buckets + bucketsNum, 0U);
580    std::fill(chains, chains + hashNum, STN_UNDEF);
581   
582    std::unique_ptr<uint32_t[]> lastNodes(new uint32_t[bucketsNum]);
583    std::fill(lastNodes.get(), lastNodes.get() + bucketsNum, UINT32_MAX);
584    for (uint32_t i = skipFirst; i < hashNum; i++)
585    {
586        const uint32_t bucket = hashCodes[i] % bucketsNum;
587        if (lastNodes[bucket] == UINT32_MAX)
588        {   // first entry of chain
589            SULEV(buckets[bucket], i);
590            lastNodes[bucket] = i;
591        }
592        else
593        {
594            SULEV(chains[lastNodes[bucket]], i);
595            lastNodes[bucket] = i;
596        }
597    }
598}
599
600template<typename Types>
601void ElfBinaryGenTemplate<Types>::generate(FastOutputBuffer& fob)
602{
603    computeSize();
604    const uint64_t startOffset = fob.getWritten();
605    /* write elf header */
606    {
607        typename Types::Ehdr ehdr;
608        ::memset(ehdr.e_ident, 0, EI_NIDENT);
609        ehdr.e_ident[0] = 0x7f;
610        ehdr.e_ident[1] = 'E';
611        ehdr.e_ident[2] = 'L';
612        ehdr.e_ident[3] = 'F';
613        ehdr.e_ident[4] = Types::ELFCLASS;
614        ehdr.e_ident[5] = ELFDATA2LSB;
615        ehdr.e_ident[6] = EV_CURRENT;
616        ehdr.e_ident[EI_OSABI] = header.osABI;
617        ehdr.e_ident[EI_ABIVERSION] = header.abiVersion;
618        SLEV(ehdr.e_type, header.type);
619        SLEV(ehdr.e_machine, header.machine);
620        SLEV(ehdr.e_version, header.version);
621        SLEV(ehdr.e_flags, header.flags);
622        if (header.entryRegion != UINT_MAX)
623        {   // if have entry
624            typename Types::Word entry = regionOffsets[header.entryRegion] + header.entry;
625            if (regions[header.entryRegion].type == ElfRegionType::SECTION &&
626                regions[header.entryRegion].section.addrBase != 0)
627                entry += regions[header.entryRegion].section.addrBase;
628            else
629                entry += header.vaddrBase;
630           
631            SLEV(ehdr.e_entry, entry);
632        }
633        else
634            SLEV(ehdr.e_entry, 0);
635        SLEV(ehdr.e_ehsize, sizeof(typename Types::Ehdr));
636        if (!progHeaders.empty())
637        {
638            SLEV(ehdr.e_phentsize, sizeof(typename Types::Phdr));
639            SLEV(ehdr.e_phoff, regionOffsets[phdrTabRegion]);
640        }
641        else
642        {
643            SLEV(ehdr.e_phentsize, 0);
644            SLEV(ehdr.e_phoff, 0);
645        }
646        SLEV(ehdr.e_phnum, progHeaders.size());
647        SLEV(ehdr.e_shentsize, sizeof(typename Types::Shdr));
648        SLEV(ehdr.e_shnum, sectionsNum);
649        SLEV(ehdr.e_shoff, regionOffsets[shdrTabRegion]);
650        SLEV(ehdr.e_shstrndx, shStrTab);
651       
652        fob.writeObject(ehdr);
653    }
654   
655    size_t nullSymNameOffset = 0;
656    // if addNullSym is not set, then no empty symbol name added, then we
657    // find first null character
658    if (!addNullSym && !symbols.empty())
659        nullSymNameOffset = ::strlen(symbols[0].name);
660    size_t nullDynSymNameOffset = 0;
661    // if addNullDynSym is not set, then no empty dynamic symbol name added, then we
662    // find first null character
663    if (!addNullDynSym && !dynSymbols.empty())
664        nullDynSymNameOffset = ::strlen(dynSymbols[0].name);
665    // if addNullSection is not set, then no empty section name added, then we
666    // find first null character
667    size_t nullSectionNameOffset = 0;
668    if (!addNullSection)
669    {
670        for (const ElfRegionTemplate<Types>& reg: regions)
671            if (reg.type == ElfRegionType::SECTION)
672            {
673                nullSectionNameOffset = ::strlen(reg.section.name);
674                break;
675            }
676    }
677   
678    /* write regions */
679    for (size_t i = 0; i < regions.size(); i++)
680    {   
681        const ElfRegionTemplate<Types>& region = regions[i];
682        // fix alignment
683        uint64_t toFill = 0;
684        typename Types::Word ralign = (region.type==ElfRegionType::SECTION) ?
685                        region.section.align : 0;
686        ralign = std::max(region.align, ralign);
687        if (ralign > 1)
688        {
689            const uint64_t curOffset = (fob.getWritten()-startOffset);
690            if (ralign!=0 && (curOffset&(ralign-1))!=0)
691                toFill = ralign - (curOffset&(ralign-1));
692            fob.fill(toFill, 0);
693        }
694        assert(regionOffsets[i] == fob.getWritten()-startOffset);
695       
696        // write content
697        if (region.type == ElfRegionType::PHDR_TABLE)
698        {   /* write program headers */
699            for (const auto& progHeader: progHeaders)
700            {
701                typename Types::Phdr phdr;
702                SLEV(phdr.p_type, progHeader.type);
703                SLEV(phdr.p_flags, progHeader.flags);
704                const ElfRegionTemplate<Types>& sregion = regions[progHeader.regionStart];
705                bool zeroOffset = sregion.type == ElfRegionType::SECTION &&
706                        sregion.section.zeroOffset;
707                SLEV(phdr.p_offset, !zeroOffset ?
708                        regionOffsets[progHeader.regionStart] : 0);
709                typename Types::Word align = (sregion.type==ElfRegionType::SECTION) ?
710                        sregion.section.align : 0;
711                align = std::max(sregion.align, align);
712                SLEV(phdr.p_align, align);
713               
714                /* paddrBase and vaddrBase is base to program header virtual and physical
715                 * addresses for program header. if not defined then get address base
716                 * from ELF header */
717                if (progHeader.paddrBase == Types::nobase)
718                    SLEV(phdr.p_paddr, regionAddresses[progHeader.regionStart]);
719                else if (progHeader.paddrBase != 0)
720                    SLEV(phdr.p_paddr, progHeader.paddrBase +
721                                regionAddresses[progHeader.regionStart]);
722                else if (header.paddrBase != 0)
723                    SLEV(phdr.p_paddr, header.paddrBase +
724                                regionAddresses[progHeader.regionStart]);
725                else
726                    SLEV(phdr.p_paddr, 0);
727               
728                if (progHeader.vaddrBase == Types::nobase)
729                    SLEV(phdr.p_vaddr, regionAddresses[progHeader.regionStart]);
730                else if (progHeader.vaddrBase != 0)
731                    SLEV(phdr.p_vaddr, progHeader.vaddrBase +
732                                regionAddresses[progHeader.regionStart]);
733                else if (header.vaddrBase != 0)
734                    SLEV(phdr.p_vaddr, header.vaddrBase +
735                                regionAddresses[progHeader.regionStart]);
736                else
737                    SLEV(phdr.p_vaddr, 0);
738               
739                // last region size for file - if nobits section then we assume zero size
740                const auto& lastReg = regions[progHeader.regionStart+
741                            progHeader.regionsNum-1];
742                uint64_t fileLastRegSize =(lastReg.type!=ElfRegionType::SECTION ||
743                    lastReg.section.type!=SHT_NOBITS) ? lastReg.size : 0;
744                /// fileSize - add offset of first region to simulate region alignment
745                const typename Types::Word fileSize = regionOffsets[progHeader.regionStart+
746                        progHeader.regionsNum-1] + fileLastRegSize -
747                        regionOffsets[progHeader.regionStart];
748                const typename Types::Word phSize = regionAddresses[progHeader.regionStart+
749                        progHeader.regionsNum-1]+regions[progHeader.regionStart+
750                        progHeader.regionsNum-1].size -
751                        regionAddresses[progHeader.regionStart];
752                SLEV(phdr.p_filesz, phSize);
753               
754                if (progHeader.haveMemSize)
755                {
756                    if (progHeader.memSize != 0)
757                        SLEV(phdr.p_memsz, progHeader.memSize);
758                    else
759                        SLEV(phdr.p_memsz, phSize);
760                }
761                else
762                    SLEV(phdr.p_memsz, 0);
763                SLEV(phdr.p_filesz, fileSize);
764                fob.writeObject(phdr);
765            }
766        }
767        else if (region.type == ElfRegionType::SHDR_TABLE)
768        {   /* write section headers table */
769            if (addNullSection)
770                fob.fill(sizeof(typename Types::Shdr), 0);
771            uint32_t nameOffset = (addNullSection);
772            for (cxuint j = 0; j < regions.size(); j++)
773            {
774                const auto& region2 = regions[j];
775                if (region2.type == ElfRegionType::SECTION)
776                {
777                    typename Types::Shdr shdr;
778                    if (region2.section.name!=nullptr && region2.section.name[0]!=0)
779                        SLEV(shdr.sh_name, nameOffset);
780                    else // set empty name offset
781                        SLEV(shdr.sh_name, nullSectionNameOffset);
782                    SLEV(shdr.sh_type, region2.section.type);
783                    SLEV(shdr.sh_flags, region2.section.flags);
784                    SLEV(shdr.sh_offset, (!region2.section.zeroOffset) ?
785                                regionOffsets[j] : 0);
786                    /* addrBase is base address of first section. if not defined
787                     * use address base as virtual address base from elf header */
788                    if (region2.section.addrBase==Types::nobase)
789                        SLEV(shdr.sh_addr, regionAddresses[j]);
790                    else if (region2.section.addrBase != 0)
791                        SLEV(shdr.sh_addr, region2.section.addrBase+regionAddresses[j]);
792                    else if (header.vaddrBase != 0)
793                        SLEV(shdr.sh_addr, header.vaddrBase+regionAddresses[j]);
794                    else
795                        SLEV(shdr.sh_addr, 0);
796                   
797                    if (region2.align != 0 || j+1 >= regions.size() ||
798                        regionOffsets[j]+region2.size == regionOffsets[j+1])
799                        SLEV(shdr.sh_size, region2.size);
800                    else
801                        SLEV(shdr.sh_size, regionOffsets[j+1]-regionOffsets[j]);
802                    SLEV(shdr.sh_info, region2.section.info);
803                    SLEV(shdr.sh_addralign, region2.align);
804                    if (region2.section.link == 0)
805                    {
806                        if (::strcmp(region2.section.name, ".symtab") == 0)
807                            SLEV(shdr.sh_link, strTab);
808                        else if (::strcmp(region2.section.name, ".dynsym") == 0)
809                            SLEV(shdr.sh_link, dynStr);
810                        else
811                            SLEV(shdr.sh_link, region2.section.link);
812                    }
813                    else
814                        SLEV(shdr.sh_link, region2.section.link);
815                   
816                    if (region2.section.type == SHT_SYMTAB ||
817                        region2.section.type == SHT_DYNSYM)
818                        SLEV(shdr.sh_entsize, sizeof(typename Types::Sym));
819                    else
820                        SLEV(shdr.sh_entsize, region2.section.entSize);
821                    if (region2.section.name!=nullptr && region2.section.name[0]!=0)
822                        nameOffset += ::strlen(region2.section.name)+1;
823                    fob.writeObject(shdr);
824                }
825            }
826        }
827        else if (region.type == ElfRegionType::USER)
828        {
829            if (region.dataFromPointer)
830                fob.writeArray(region.size, region.data);
831            else
832                (*region.dataGen)(fob);
833        }
834        else if (region.type == ElfRegionType::SECTION)
835        {
836            if (region.data == nullptr)
837            {
838                if (region.section.type == SHT_SYMTAB || region.section.type == SHT_DYNSYM)
839                {
840                    uint32_t nameOffset = 0;
841                    if (region.section.type == SHT_SYMTAB && addNullSym)
842                    {
843                        fob.fill(sizeof(typename Types::Sym), 0);
844                        nameOffset = 1;
845                    }
846                    if (region.section.type == SHT_DYNSYM && addNullDynSym)
847                    {
848                        fob.fill(sizeof(typename Types::Sym), 0);
849                        nameOffset = 1;
850                    }
851                    const auto& symbolsList = (region.section.type == SHT_SYMTAB) ?
852                            symbols : dynSymbols;
853                    for (const auto& inSym: symbolsList)
854                    {
855                        typename Types::Sym sym;
856                        if (inSym.name != nullptr && inSym.name[0] != 0)
857                            SLEV(sym.st_name, nameOffset);
858                        else  // set empty name offset (symbol or dynamic symbol)
859                            SLEV(sym.st_name, (region.section.type == SHT_SYMTAB) ?
860                                        nullSymNameOffset : nullDynSymNameOffset);
861                       
862                        SLEV(sym.st_shndx, inSym.sectionIndex);
863                        SLEV(sym.st_size, inSym.size);
864                        /// if value defined as address
865                        if (!inSym.valueIsAddr)
866                            SLEV(sym.st_value, inSym.value);
867                        // if not use conversion to address with section addrBase
868                        else if (inSym.sectionIndex != 0 && 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.