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