1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <libelf64/writer.h>
18 
19 #include <libelf64/elf64.h>
20 
21 #include <stdlib.h>
22 #include <fstream>
23 #include <iostream>
24 #include <string>
25 #include <vector>
26 
27 #include <elf.h>
28 
29 namespace android {
30 namespace elf64 {
31 
WriteElf64File(const Elf64Binary & elf64Binary,const std::string & fileName)32 void Elf64Writer::WriteElf64File(const Elf64Binary& elf64Binary, const std::string& fileName) {
33     std::cout << "Writing ELF64 binary to file " << fileName << std::endl;
34 
35     Elf64Writer elf64Writer(fileName);
36     elf64Writer.WriteHeader(elf64Binary.ehdr);
37     elf64Writer.WriteProgramHeaders(elf64Binary.phdrs, elf64Binary.ehdr.e_phoff);
38     elf64Writer.WriteSections(elf64Binary.sections, elf64Binary.shdrs);
39     elf64Writer.WriteSectionHeaders(elf64Binary.shdrs, elf64Binary.ehdr.e_shoff);
40 }
41 
Elf64Writer(const std::string & fileName)42 Elf64Writer::Elf64Writer(const std::string& fileName) {
43     elf64stream.open(fileName.c_str(), std::ofstream::out | std::ofstream::binary);
44     if (!elf64stream) {
45         std::cerr << "Failed to open the file: " << fileName << std::endl;
46         exit(-1);
47     }
48 }
49 
WriteHeader(const Elf64_Ehdr & ehdr)50 void Elf64Writer::WriteHeader(const Elf64_Ehdr& ehdr) {
51     Write((char*)&ehdr, sizeof(ehdr));
52 }
53 
WriteProgramHeaders(const std::vector<Elf64_Phdr> & phdrs,const Elf64_Off phoff)54 void Elf64Writer::WriteProgramHeaders(const std::vector<Elf64_Phdr>& phdrs, const Elf64_Off phoff) {
55     elf64stream.seekp(phoff);
56 
57     for (int i = 0; i < phdrs.size(); i++) {
58         Write((char*)&phdrs[i], sizeof(phdrs[i]));
59     }
60 }
61 
WriteSectionHeaders(const std::vector<Elf64_Shdr> & shdrs,const Elf64_Off shoff)62 void Elf64Writer::WriteSectionHeaders(const std::vector<Elf64_Shdr>& shdrs, const Elf64_Off shoff) {
63     elf64stream.seekp(shoff);
64 
65     for (int i = 0; i < shdrs.size(); i++) {
66         Write((char*)&shdrs[i], sizeof(shdrs[i]));
67     }
68 }
69 
WriteSections(const std::vector<Elf64_Sc> & sections,const std::vector<Elf64_Shdr> & shdrs)70 void Elf64Writer::WriteSections(const std::vector<Elf64_Sc>& sections,
71                                 const std::vector<Elf64_Shdr>& shdrs) {
72     for (int i = 0; i < sections.size(); i++) {
73         if (shdrs[i].sh_type == SHT_NOBITS) {
74             // Skip .bss section because it is empty.
75             continue;
76         }
77 
78         // Move the cursor position to offset provided by the section header.
79         elf64stream.seekp(shdrs[i].sh_offset);
80 
81         Write(sections[i].data.data(), sections[i].size);
82     }
83 }
84 
Write(const char * const data,const std::streamsize size)85 void Elf64Writer::Write(const char* const data, const std::streamsize size) {
86     elf64stream.write(data, size);
87     if (!elf64stream) {
88         std::cerr << "Failed to write [" << size << "] bytes" << std::endl;
89         exit(-1);
90     }
91 }
92 
93 }  // namespace elf64
94 }  // namespace android
95