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

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

CLRadeonExtender: Apply Elf notes support in AmdCL2BinGen. write name with zero while storing note in elf (ElfBinGen?).
Add constructors to ElfNote?.

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