1 /*========================== begin_copyright_notice ============================
2 
3 Copyright (C) 2017-2021 Intel Corporation
4 
5 SPDX-License-Identifier: MIT
6 
7 ============================= end_copyright_notice ===========================*/
8 
9 #include "ElfWriter.h"
10 #include "secure_mem.h" // needed for memcpy_s on linux/android
11 #include <cstring>
12 
13 namespace CLElfLib
14 {
15 /******************************************************************************\
16  Constructor: CElfWriter::CElfWriter
17 \******************************************************************************/
CElfWriter(E_EH_TYPE type,E_EH_MACHINE machine,Elf64_Xword flags)18 CElfWriter::CElfWriter(
19     E_EH_TYPE type,
20     E_EH_MACHINE machine,
21     Elf64_Xword flags )
22 {
23     m_type = type;
24     m_machine = machine;
25     m_flags = flags;
26     m_dataSize = 0;
27     m_numSections = 0;
28     m_stringTableSize = 0;
29 }
30 
31 /******************************************************************************\
32  Destructor: CElfWriter::~CElfWriter
33 \******************************************************************************/
~CElfWriter()34 CElfWriter::~CElfWriter()
35 {
36     SSectionNode* pNode = NULL;
37 
38     // Walk through the section nodes
39     while( m_nodeQueue.empty() == false )
40     {
41         pNode = m_nodeQueue.front();
42         m_nodeQueue.pop();
43 
44         // delete the node and it's data
45         if( pNode )
46         {
47             if( pNode->pData )
48             {
49                 delete[] pNode->pData;
50                 pNode->pData = NULL;
51             }
52 
53             delete pNode;
54         }
55     }
56 }
57 
58 /******************************************************************************\
59  Member Function: CElfWriter::Create
60 \******************************************************************************/
Create(E_EH_TYPE type,E_EH_MACHINE machine,Elf64_Xword flags)61 CElfWriter* CElfWriter::Create(
62     E_EH_TYPE type,
63     E_EH_MACHINE machine,
64     Elf64_Xword flags )
65 {
66     CElfWriter* pWriter = new CElfWriter(
67         type, machine, flags );
68 
69     if( ( pWriter ) && ( pWriter->Initialize() != SUCCESS ) )
70     {
71         Delete( pWriter );
72     }
73 
74     return pWriter;
75 }
76 
77 /******************************************************************************\
78  Member Function: CElfWriter::Delete
79 \******************************************************************************/
Delete(CElfWriter * & pWriter)80 void CElfWriter::Delete(
81     CElfWriter* &pWriter )
82 {
83     if( pWriter )
84     {
85         delete pWriter;
86         pWriter = NULL;
87     }
88 }
89 
90 /******************************************************************************\
91  Member Function: CElfWriter::AddSection
92 \******************************************************************************/
AddSection(SSectionNode * pSectionNode)93 E_RETVAL CElfWriter::AddSection(
94     SSectionNode* pSectionNode )
95 {
96     E_RETVAL retVal = SUCCESS;
97     SSectionNode* pNode = NULL;
98     size_t nameSize = 0;
99     unsigned int dataSize = 0;
100 
101     // The section header must be non-NULL
102     if( pSectionNode )
103     {
104         pNode = new SSectionNode();
105 
106         if( !pNode )
107         {
108             retVal = OUT_OF_MEMORY;
109         }
110     }
111     else
112     {
113         retVal = FAILURE;
114     }
115 
116     if( retVal == SUCCESS )
117     {
118         pNode->Flags = pSectionNode->Flags;
119         pNode->Type  = pSectionNode->Type;
120 
121         nameSize = pSectionNode->Name.size() + 1;
122         dataSize = pSectionNode->DataSize;
123 
124         pNode->Name = pSectionNode->Name;
125 
126         // ok to have NULL data
127         if( dataSize > 0 )
128         {
129             pNode->pData = new char[dataSize];
130 
131             if( pNode->pData )
132             {
133                 memcpy_s( pNode->pData, dataSize, pSectionNode->pData, dataSize );
134                 pNode->DataSize = dataSize;
135             }
136             else
137             {
138                 retVal = OUT_OF_MEMORY;
139             }
140         }
141 
142         if( retVal == SUCCESS )
143         {
144             // push the node onto the queue
145             m_nodeQueue.push( pNode );
146 
147             // increment the sizes for each section
148             m_dataSize += dataSize;
149             m_stringTableSize += nameSize;
150             m_numSections++;
151         }
152         else
153         {
154             // cleanup allocations
155             if( pNode )
156             {
157                 if( pNode->pData )
158                 {
159                     delete[] pNode->pData;
160                     pNode->pData = NULL;
161                 }
162 
163                 delete pNode;
164             }
165         }
166     }
167 
168     return retVal;
169 }
170 
171 /******************************************************************************\
172  Member Function: CElfWriter::ResolveBinary
173 \******************************************************************************/
ResolveBinary(char * const pBinary,size_t & binarySize)174 E_RETVAL CElfWriter::ResolveBinary(
175     char* const pBinary,
176     size_t& binarySize )
177 {
178     E_RETVAL retVal = SUCCESS;
179     SSectionNode* pNode = NULL;
180     SElf64SectionHeader* pCurSectionHeader = NULL;
181     char* pData = NULL;
182     char* pStringTable = NULL;
183     char* pCurString = NULL;
184 
185     m_totalBinarySize =
186         sizeof( SElf64Header ) +
187         ( ( m_numSections + 1 ) * sizeof( SElf64SectionHeader ) ) + // +1 to account for string table entry
188         m_dataSize +
189         m_stringTableSize;
190 
191     if( pBinary )
192     {
193         // get a pointer to the first section header
194         pCurSectionHeader = (SElf64SectionHeader*)( pBinary + sizeof( SElf64Header ) );
195 
196         // get a pointer to the data
197         pData = pBinary +
198             sizeof( SElf64Header ) +
199             ( ( m_numSections + 1 ) * sizeof( SElf64SectionHeader ) ); // +1 to account for string table entry
200 
201 
202         // get a pointer to the string table
203         pStringTable = pBinary + sizeof( SElf64Header ) +
204             ( ( m_numSections + 1 ) * sizeof( SElf64SectionHeader ) ) + // +1 to account for string table entry
205             m_dataSize ;
206 
207         pCurString = pStringTable;
208 
209         // Walk through the section nodes
210         while( m_nodeQueue.empty() == false )
211         {
212             pNode = m_nodeQueue.front();
213 
214             if( pNode )
215             {
216                 m_nodeQueue.pop();
217 
218                 // Copy data into the section header
219                 memset( pCurSectionHeader, 0, sizeof( SElf64SectionHeader ) );
220                 pCurSectionHeader->Type = pNode->Type;
221                 pCurSectionHeader->Flags = pNode->Flags;
222                 pCurSectionHeader->DataSize = pNode->DataSize;
223                 pCurSectionHeader->DataOffset = pData - pBinary;
224                 pCurSectionHeader->Name = (Elf64_Word)( pCurString - pStringTable );
225                 pCurSectionHeader = (SElf64SectionHeader*)(
226                     (unsigned char*)pCurSectionHeader + sizeof( SElf64SectionHeader ) );
227 
228                 // copy the data, move the data pointer
229                 memcpy_s( pData, pNode->DataSize, pNode->pData, pNode->DataSize );
230                 pData += pNode->DataSize;
231 
232                 // copy the name into the string table, move the string pointer
233                 if ( pNode->Name.size() > 0 )
234                 {
235                     memcpy_s( pCurString, pNode->Name.size(), pNode->Name.c_str(), pNode->Name.size() );
236                     pCurString += pNode->Name.size();
237                 }
238                 *(pCurString++) = '\0';
239 
240                 // delete the node and it's data
241                 if( pNode )
242                 {
243                     if( pNode->pData )
244                     {
245                         delete[] pNode->pData;
246                         pNode->pData = NULL;
247                     }
248 
249                     delete pNode;
250                 }
251             }
252         }
253 
254         // add the string table section header
255         SElf64SectionHeader stringSectionHeader = { 0 };
256         stringSectionHeader.Type = SH_TYPE_STR_TBL;
257         stringSectionHeader.Flags = 0;
258         stringSectionHeader.DataOffset = pStringTable - pBinary;
259         stringSectionHeader.DataSize = m_stringTableSize;
260         stringSectionHeader.Name = 0;
261 
262         // Copy into the last section header
263         memcpy_s( pCurSectionHeader, sizeof( SElf64SectionHeader ),
264             &stringSectionHeader, sizeof( SElf64SectionHeader ) );
265 
266         // Add to our section number
267         m_numSections++;
268 
269         // patch up the ELF header
270         retVal = PatchElfHeader( pBinary );
271     }
272 
273     if( retVal == SUCCESS )
274     {
275         binarySize = m_totalBinarySize;
276     }
277 
278     return retVal;
279 }
280 
281 /******************************************************************************\
282  Member Function: CElfWriter::Initialize
283 \******************************************************************************/
Initialize()284 E_RETVAL CElfWriter::Initialize()
285 {
286     E_RETVAL retVal = SUCCESS;
287     SSectionNode emptySection;
288 
289     // Add an empty section 0 (points to "no-bits")
290     AddSection( &emptySection );
291 
292     return retVal;
293 }
294 
295 /******************************************************************************\
296  Member Function: CElfWriter::PatchElfHeader
297 \******************************************************************************/
PatchElfHeader(char * const pBinary)298 E_RETVAL CElfWriter::PatchElfHeader( char* const pBinary )
299 {
300     E_RETVAL   retVal   = SUCCESS;
301     SElf64Header* pElfHeader = (SElf64Header*)pBinary;
302 
303     if( pElfHeader )
304     {
305         // Setup the identity
306         memset( pElfHeader, 0x00, sizeof( SElf64Header ) );
307         pElfHeader->Identity[ID_IDX_MAGIC0]       = ELF_MAG0;
308         pElfHeader->Identity[ID_IDX_MAGIC1]       = ELF_MAG1;
309         pElfHeader->Identity[ID_IDX_MAGIC2]       = ELF_MAG2;
310         pElfHeader->Identity[ID_IDX_MAGIC3]       = ELF_MAG3;
311         pElfHeader->Identity[ID_IDX_CLASS]        = EH_CLASS_64;
312         pElfHeader->Identity[ID_IDX_VERSION]      = EH_VERSION_CURRENT;
313 
314         // Add other non-zero info
315         pElfHeader->Type = m_type;
316         pElfHeader->Machine = m_machine;
317         pElfHeader->Flags = (unsigned int)m_flags;
318         pElfHeader->ElfHeaderSize = sizeof( SElf64Header );
319         pElfHeader->SectionHeaderEntrySize = sizeof( SElf64SectionHeader );
320         pElfHeader->NumSectionHeaderEntries = (Elf64_Short)m_numSections;
321         pElfHeader->SectionHeadersOffset = (unsigned int)( sizeof( SElf64Header ) );
322         pElfHeader->SectionNameTableIndex = m_numSections-1; // last index
323     }
324 
325     return retVal;
326 }
327 
328 } // namespace OclElfLib
329