1 /*
2 * Copyright (C) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include <cstddef>
16 #include <string.h>
17 #include <inttypes.h>
18 #include <algorithm>
19 #include <memory>
20 #include <string>
21 #include <string_view>
22 #include <vector>
23 #include <set>
24 #include "dir.h"
25 #include "coff.h"
26 #include "elf32.h"
27 #include "elf64.h"
28
29 #ifdef __APPLE__
30 #include <mach-o/loader.h>
31 #include <mach-o/nlist.h>
32 #include <mach-o/fat.h>
33 #endif
34
35 struct FsEntry {
36 char fname[256];
37 uint64_t offset;
38 uint64_t size;
39 };
40
41 std::vector<FsEntry> g_directory;
42 std::vector<uint8_t> g_bin;
43 std::vector<std::string_view> g_validExts;
44
AppendFile(const std::string & filename,const std::string & storename)45 void AppendFile(const std::string& filename, const std::string& storename)
46 {
47 std::string_view ext;
48 auto pos = filename.find_last_of(".");
49 if (pos != std::string::npos) {
50 // found it.
51 ext = std::string_view(filename).substr(pos);
52 }
53 bool valid = false;
54 for (const auto& e : g_validExts) {
55 if (ext.compare(e) == 0) {
56 valid = true;
57 break;
58 }
59 }
60 if (!valid) {
61 printf("Skipped %s\n", storename.c_str());
62 return;
63 }
64 if (storename.size() > (sizeof(FsEntry::fname) - 1u)) {
65 printf("Filename too long [%s]\n", storename.c_str());
66 exit(-1);
67 }
68 FsEntry tmp{};
69 tmp.fname[storename.copy(tmp.fname, sizeof(tmp.fname) - 1u)] = '\0';
70 #if _WIN32
71 struct _stat64 fileStat;
72 if (_stat64(filename.c_str(), &fileStat) == -1) {
73 #else
74 struct stat fileStat;
75 if (stat(filename.c_str(), &fileStat) == -1) {
76 #endif
77 printf("File [%s] not found\n", tmp.fname);
78 exit(-1);
79 }
80 tmp.size = fileStat.st_size;
81 auto padding = (8 - (g_bin.size() & 7)) & 7;
82 tmp.offset = g_bin.size() + padding;
83 g_directory.push_back(tmp);
84 FILE* f = fopen(filename.c_str(), "rb");
85 if (f == nullptr) {
86 printf("Could not open %s.\n", filename.c_str());
87 exit(-1);
88 }
89 g_bin.resize(static_cast<size_t>(g_bin.size() + padding + tmp.size));
90 fread(g_bin.data() + tmp.offset, 1, static_cast<size_t>(tmp.size), f);
91 fclose(f);
92 printf("Stored: %s [%" PRIu64 " , %" PRIu64 "]\n", tmp.fname, tmp.offset, tmp.size);
93 }
94
95 void AddDirectory(const std::string& path, const std::string& outpath)
96 {
97 struct dirent* pDirent = nullptr;
98 DIR* pDir = opendir(path.c_str());
99 if (pDir == nullptr) {
100 printf("Cannot open directory '%s'\n", path.c_str());
101 exit(1);
102 }
103 std::string p, op;
104 p = path;
105 if (!p.empty()) {
106 if (p.back() != '/') {
107 p += "/";
108 }
109 }
110 op = outpath;
111 if (!op.empty()) {
112 if (op.back() != '/') {
113 op += "/";
114 }
115 }
116
117 // sort the readdir result
118 auto alphaSort = [](dirent* x, dirent* y) { return std::string(x->d_name) < std::string(y->d_name); };
119 auto dirSet = std::set<dirent*, decltype(alphaSort)>(alphaSort);
120
121 while ((pDirent = readdir(pDir)) != nullptr) {
122 // This structure may be statically allocated
123 dirSet.insert(pDirent);
124 }
125
126 for (auto &d : dirSet) {
127 if (d->d_type == DT_DIR) {
128 if (d->d_name[0] == '.') {
129 continue;
130 }
131 AddDirectory(p + d->d_name, op + d->d_name);
132 continue;
133 }
134 AppendFile(p + d->d_name, op + d->d_name);
135 }
136
137 closedir(pDir);
138 }
139 /*
140 * //Pseudo code for accessing files in blob
141 * struct fs_entry
142 * {
143 * char fname[256];
144 * uint64_t offset;
145 * uint64_t size;
146 * };
147 * extern "C" uint64_t SizeOfDataForReadOnlyFileSystem;
148 * extern "C" struct fs_entry BinaryDataForReadOnlyFileSystem[];
149 * void dump_files()
150 * {
151 * for (int i = 0; i < SizeOfDataForReadOnlyFileSystem; i++)
152 * {
153 * if (BinaryDataForReadOnlyFileSystem[i].fname[0] == 0) break;
154 * printf("%s\n", BinaryDataForReadOnlyFileSystem[i].fname);
155 * char* data = (char*)(BinaryDataForReadOnlyFileSystem[i].offset +
156 * (uintptr_t)BinaryDataForReadOnlyFileSystem); printf("%lld\n", BinaryDataForReadOnlyFileSystem[i].offset);
157 * }
158 * }
159 */
160
161 std::string g_dataName = "BinaryDataForReadOnlyFileSystem";
162 std::string g_sizeName = "SizeOfDataForReadOnlyFileSystem";
163
164 void WriteObj(const std::string& fname, const std::string& secname, size_t sizeOfData, const void* data, bool x64)
165 {
166 size_t sizeOfSection = sizeof(uint64_t) + sizeOfData;
167 #pragma pack(push, 1)
168 // Using headers and defines from winnt.h
169 struct ObjFile {
170 IMAGE_FILE_HEADER coffHead;
171 IMAGE_SECTION_HEADER sections[1];
172 IMAGE_SYMBOL symtab[2];
173 } obj{};
174 #pragma pack(pop)
175
176 // fill coff header.
177 if (!x64) {
178 obj.coffHead.Machine = IMAGE_FILE_MACHINE_I386;
179 } else {
180 obj.coffHead.Machine = IMAGE_FILE_MACHINE_AMD64;
181 }
182 obj.coffHead.NumberOfSections = sizeof(obj.sections) / sizeof(IMAGE_SECTION_HEADER);
183 obj.coffHead.TimeDateStamp = 0; // duh.
184 obj.coffHead.PointerToSymbolTable = offsetof(decltype(obj), symtab);
185 obj.coffHead.NumberOfSymbols = sizeof(obj.symtab) / sizeof(IMAGE_SYMBOL);
186 obj.coffHead.SizeOfOptionalHeader = 0;
187 obj.coffHead.Characteristics = 0; // if x86 use IMAGE_FILE_32BIT_MACHINE ?
188
189 // create stringtable
190 char stringtable[256]{ 0 };
191 char* dst = stringtable;
192 auto addString = [&dst, &stringtable](std::string_view a) -> Elf32_Word {
193 const auto offset = dst - stringtable;
194 dst += a.copy(dst, 256u - offset);
195 *dst++ = '\0';
196 return static_cast<uint32_t>(offset + 4);
197 };
198 if (!x64) {
199 // in win32 the symbols have extra "_" ?
200 std::string t = "_";
201 t += g_dataName;
202 std::string t2 = "_";
203 t2 += g_sizeName;
204 obj.symtab[1].N.Name.Long = addString(t.c_str() /*"BinaryDataForReadOnlyFileSystem"*/);
205 obj.symtab[0].N.Name.Long = addString(t2.c_str() /*"SizeOfDataForReadOnlyFileSystem"*/);
206 } else {
207 obj.symtab[1].N.Name.Long = addString(g_dataName.c_str() /*"BinaryDataForReadOnlyFileSystem"*/);
208 obj.symtab[0].N.Name.Long = addString(g_sizeName.c_str() /*"SizeOfDataForReadOnlyFileSystem"*/);
209 }
210 uint32_t stringTableSize = static_cast<uint32_t>((dst - stringtable) + 4);
211
212 // fill the section.
213 std::copy(secname.c_str(), secname.c_str() + secname.size(), &obj.sections[0].Name[0]);
214 obj.sections[0].Name[secname.size()] = '\0';
215 obj.sections[0].Misc.VirtualSize = 0;
216 obj.sections[0].VirtualAddress = 0;
217 obj.sections[0].SizeOfRawData = static_cast<uint32_t>(sizeOfSection); // sizeof the data on disk.
218 obj.sections[0].PointerToRawData =
219 ((sizeof(obj) + stringTableSize + 3u) / 4u) * 4u; // DWORD align the data directly after the headers..
220 obj.sections[0].PointerToLinenumbers = 0;
221 obj.sections[0].NumberOfRelocations = 0;
222 obj.sections[0].NumberOfLinenumbers = 0;
223 obj.sections[0].Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ;
224 // fill symbols
225 obj.symtab[1].Value = static_cast<uint32_t>(sizeof(uint64_t));
226 obj.symtab[1].SectionNumber = 1; // first section.. (one based)
227 obj.symtab[1].Type = IMAGE_SYM_TYPE_CHAR | (IMAGE_SYM_DTYPE_ARRAY << 8);
228 obj.symtab[1].StorageClass = IMAGE_SYM_CLASS_EXTERNAL;
229 obj.symtab[1].NumberOfAuxSymbols = 0;
230
231 obj.symtab[0].Value = static_cast<uint32_t>(0u);
232 obj.symtab[0].SectionNumber = 1; // first section.. (one based)
233 // obj.symtab[0].Type = IMAGE_SYM_TYPE_UINT; //(just use IMAGE_SYM_TYPE_NULL like mstools?)
234 obj.symtab[0].StorageClass = IMAGE_SYM_CLASS_EXTERNAL;
235 obj.symtab[0].NumberOfAuxSymbols = 0;
236
237 FILE* d = fopen(fname.c_str(), "wb");
238 if (d == nullptr) {
239 printf("Could not open %s.\n", fname.c_str());
240 exit(-1);
241 }
242 // write headers
243 fwrite(&obj, sizeof(obj), 1u, d);
244 // write string table
245 fwrite(&stringTableSize, 1, sizeof(stringTableSize), d);
246 fwrite(stringtable, 1, stringTableSize - 4, d);
247 // write sections..
248 size_t p = ftell(d);
249 uint32_t pad = 0;
250 size_t padcount = obj.sections[0].PointerToRawData - p;
251 fwrite(&pad, padcount, 1u, d);
252 fwrite(data, sizeOfSection, 1u, d);
253 fclose(d);
254 #undef addString
255 }
256
257 template<class type>
258 void WriteElf(
259 type o, uint8_t arch, const std::string& fname, const std::string& secname, size_t sizeOfData, const void* data)
260 {
261 size_t sizeOfSection = sizeOfData + sizeof(uint64_t);
262 char stringtable[256];
263 o.head.e_type = ET_REL;
264 o.head.e_machine = arch; // machine id..
265 o.head.e_version = EV_CURRENT;
266 o.head.e_ehsize = sizeof(o.head);
267 o.head.e_shentsize = sizeof(o.sections[0]);
268 o.head.e_shnum = sizeof(o.sections) / sizeof(o.sections[0]);
269 o.head.e_shoff = sizeof(o.head);
270 o.head.e_shstrndx = 1;
271
272 // initialize stringtable.
273 char* dst = stringtable;
274 *dst = 0;
275 dst++;
276 auto addString = [&dst, &stringtable](std::string_view a) -> Elf32_Word {
277 const auto offset = dst - stringtable;
278 dst += a.copy(dst, 256u - offset);
279 *dst++ = '\0';
280 return static_cast<Elf32_Word>(offset);
281 };
282
283 // create symbols
284 o.symbs[2].st_name = addString(g_dataName); // ?BinaryDataForReadOnlyFileSystem@@3PADA");
285 o.symbs[2].st_value = sizeof(uint64_t);
286 o.symbs[2].st_size = static_cast<Elf32_Word>(sizeOfData);
287 o.symbs[2].st_info = o.symbs[1].st_info = ELF_ST_INFO(STB_GLOBAL, STT_OBJECT);
288 o.symbs[2].st_other = o.symbs[1].st_other = STV_HIDDEN;
289 o.symbs[2].st_shndx = o.symbs[1].st_shndx = 3;
290
291 o.symbs[1].st_name = addString(g_sizeName);
292 o.symbs[1].st_value = 0;
293 o.symbs[1].st_size = sizeof(uint64_t);
294
295 o.sections[2].sh_name = addString(".symtab");
296 o.sections[2].sh_type = SHT_SYMTAB;
297 o.sections[2].sh_offset = offsetof(decltype(o), symbs); // sizeof(o) + sizeOfSection + stringtable_size;
298 o.sections[2].sh_addralign = 8;
299 o.sections[2].sh_size = sizeof(o.symbs);
300 o.sections[2].sh_entsize = sizeof(o.symbs[0]);
301 o.sections[2].sh_link = 1;
302 o.sections[2].sh_info = 1; // index of first non-local symbol.
303
304 std::string tmp = ".rodata.";
305 tmp += secname;
306 /*sec = ".rodata.rofs"*/
307 o.sections[3].sh_name = addString(tmp);
308 o.sections[3].sh_type = SHT_PROGBITS;
309 o.sections[3].sh_flags = SHF_ALLOC | SHF_MERGE;
310 o.sections[3].sh_offset = sizeof(o);
311 o.sections[3].sh_addralign = 8;
312 o.sections[3].sh_size = static_cast<Elf32_Word>(sizeOfSection);
313
314 o.sections[1].sh_name = addString(".strtab");
315 o.sections[1].sh_type = SHT_STRTAB;
316 o.sections[1].sh_offset = static_cast<Elf32_Off>(sizeof(o) + sizeOfSection);
317 o.sections[1].sh_addralign = 1;
318 o.sections[1].sh_size = static_cast<Elf32_Word>(dst - stringtable);
319
320 FILE* e = fopen(fname.c_str(), "wb");
321 if (e == nullptr) {
322 printf("Could not open %s.\n", fname.c_str());
323 exit(-1);
324 }
325 fwrite(&o, sizeof(o), 1, e);
326 fwrite(data, sizeOfSection, 1, e);
327 fwrite(stringtable, static_cast<size_t>(o.sections[1].sh_size), 1, e);
328 fclose(e);
329 }
330
331 void WriteMacho(const std::string& fname, const std::string& secname, size_t sizeOfData, const void* data)
332 {
333 #ifdef __APPLE__
334 // Write fat header for X64_64 and ARM64 object
335 struct fat_header fathdr;
336 fathdr.magic = FAT_CIGAM;
337 fathdr.nfat_arch = htonl(2); // big-endian values in fat header
338
339 struct fat_arch archs[2] = {
340 {
341 htonl(CPU_TYPE_X86_64),
342 htonl(CPU_SUBTYPE_X86_64_ALL),
343 0,
344 0, // size of data
345 htonl(3)
346 },
347 {
348 htonl(CPU_TYPE_ARM64),
349 htonl(CPU_SUBTYPE_ARM64_ALL),
350 0, // offset,
351 0, // size of data
352 htonl(3)
353 },
354 };
355
356 size_t fpos = 0; // "file" offsets are actually relative to the architecture header
357 archs[0].offset = htonl(sizeof(fathdr) + sizeof(archs));
358
359 size_t sizeOfSection = sizeOfData + sizeof(uint64_t);
360
361 struct mach_header_64 x64_header = {
362 MH_MAGIC_64,
363 CPU_TYPE_X86_64,
364 CPU_SUBTYPE_X86_64_ALL,
365 MH_OBJECT,
366 2, // ncmds
367 sizeof(segment_command_64) + sizeof(section_64) + sizeof(symtab_command), // sizeofcmds
368 0, // flags
369 0 // reserved
370 };
371
372 struct mach_header_64 arm64_header = {
373 MH_MAGIC_64,
374 CPU_TYPE_ARM64,
375 CPU_SUBTYPE_ARM64_ALL,
376 MH_OBJECT,
377 2, // ncmds
378 sizeof(segment_command_64) + sizeof(section_64) + sizeof(symtab_command), // sizeofcmds
379 0, // flags
380 0 // reserved
381 };
382
383 struct segment_command_64 data_seg = {
384 LC_SEGMENT_64,
385 sizeof(data_seg) + sizeof(section_64),
386 "", // for object files name is empty
387 0, // vmaddress
388 (sizeOfSection + 7) & ~7, // vmsize aligned to 8 bytes
389 0, // fileoffset
390 sizeOfSection, // filesize
391 VM_PROT_READ, // maxprot
392 VM_PROT_READ, // initprot
393 1, // nsects
394 SG_NORELOC // flags
395 };
396
397 struct section_64 data_sect = {
398 "__const",
399 "__DATA",
400 0, // addr
401 sizeOfSection, // vmsize aligned to 8 bytes
402 0, // offset
403 3, // alignment = 2^3 = 8 bytes
404 0, // reloff
405 0, // nreloc
406 S_REGULAR, // flags
407 0, // reserved1
408 0, // reserved2
409 };
410
411 std::string dataName = "_";
412 dataName += g_dataName;
413 std::string sizeName = "_";
414 sizeName += g_sizeName;
415
416 uint32_t string_size = dataName.size() + sizeName.size() + 3; // prepending plus two terminating nulls
417
418 struct symtab_command symtab = {
419 LC_SYMTAB,
420 sizeof(symtab),
421 0, // symoff
422 2, // nsyms
423 0, // stroff
424 string_size, // strsize
425 };
426
427 fpos += sizeof(x64_header) + sizeof(data_seg) + sizeof(data_sect) + sizeof(symtab);
428
429 data_seg.fileoff = static_cast<uint32_t>(fpos);
430 data_sect.offset = static_cast<uint32_t>(fpos);
431 fpos += sizeOfSection;
432
433 size_t sectionAligned = (fpos + 7) & ~7;
434 uint32_t sectionAlign = sectionAligned - fpos;
435 fpos = sectionAligned;
436
437 symtab.symoff = static_cast<uint32_t>(fpos);
438
439 struct nlist_64 syms[2] = {
440 {
441 1, // first string
442 N_EXT | N_SECT,
443 1, // segment
444 REFERENCE_FLAG_DEFINED,
445 0
446 },
447 {
448 static_cast<uint32_t>(sizeName.size() + 2), // second string
449 N_EXT | N_SECT,
450 1, // segment
451 REFERENCE_FLAG_DEFINED,
452 8
453 }
454 };
455
456 fpos += sizeof(syms);
457
458 symtab.stroff = static_cast<uint32_t>(fpos);
459 fpos += string_size;
460
461 archs[0].size = htonl(fpos);
462
463 size_t aligned = (fpos + 7) & ~7;
464 uint32_t align = aligned - fpos;
465 archs[1].offset = htonl(aligned + sizeof(fathdr) + sizeof(archs));
466 archs[1].size = archs[0].size;
467
468 FILE* e = fopen(fname.c_str(), "wb");
469 if (e == NULL) {
470 printf("Could not open %s.\n", fname.c_str());
471 exit(-1);
472 }
473
474 fwrite(&fathdr, sizeof(fathdr), 1, e);
475 fwrite(&archs, sizeof(archs), 1, e);
476 fwrite(&x64_header, sizeof(x64_header), 1, e);
477 fwrite(&data_seg, sizeof(data_seg), 1, e);
478 fwrite(&data_sect, sizeof(data_sect), 1, e);
479 fwrite(&symtab, sizeof(symtab), 1, e);
480 fwrite(data, sizeOfSection, 1, e);
481 for (int i = 0; i < sectionAlign; i++) {
482 fputc(0, e); // alignment byte to begin string table 8 byte boundary
483 }
484 fwrite(&syms, sizeof(syms), 1, e);
485 fputc(0, e); // filler byte to begin string table as it starts indexing at 1
486 fwrite(sizeName.c_str(), sizeName.size() + 1, 1, e);
487 fwrite(dataName.c_str(), dataName.size() + 1, 1, e);
488
489 for (int i = 0; i < align; i++) {
490 fputc(0, e); // alignment byte to begin arm64 architecture at 8 byte boundary
491 }
492
493 fwrite(&arm64_header, sizeof(arm64_header), 1, e);
494 fwrite(&data_seg, sizeof(data_seg), 1, e);
495 fwrite(&data_sect, sizeof(data_sect), 1, e);
496 fwrite(&symtab, sizeof(symtab), 1, e);
497 fwrite(data, sizeOfSection, 1, e);
498 for (int i = 0; i < sectionAlign; i++) {
499 fputc(0, e); // alignment byte to begin string table 8 byte boundary
500 }
501 fwrite(&syms, sizeof(syms), 1, e);
502 fputc(0, e); // filler byte to begin string table
503 fwrite(sizeName.c_str(), sizeName.size() + 1, 1, e);
504 fwrite(dataName.c_str(), dataName.size() + 1, 1, e);
505 fclose(e);
506 #endif
507 }
508
509 int main(int argc, char* argv[])
510 {
511 std::string obj32Name = "rofs_32.obj";
512 std::string obj64Name = "rofs_64.obj";
513 std::string o32Name = "rofs_32.o";
514 std::string o64Name = "rofs_64.o";
515 std::string x32Name = "rofs_x86.o";
516 std::string x64Name = "rofs_x64.o";
517 std::string macName = "rofs_mac.o";
518 std::string secName = "rofs";
519
520 bool buildX86 = true, buildX64 = true, buildV7 = true, buildV8 = true;
521 bool buildWindows = true, buildAndroid = true, buildMac = true;
522
523 std::string inPath = { "" }, roPath = { "" };
524
525 int baseArg = 0;
526 if (argc >= 2) {
527 if (argv[1][0] == '-') {
528 buildAndroid = false;
529 buildWindows = false;
530 buildMac = false;
531 buildX86 = buildX64 = buildV7 = buildV8 = false;
532 }
533 bool platset = false;
534 for (;;) {
535 if (baseArg + 1 >= argc) {
536 printf("Invalid argument!\n");
537 return 0;
538 }
539 if (argv[baseArg + 1][0] != '-')
540 break;
541 if (strcmp(argv[baseArg + 1], "-linux") == 0) {
542 platset = true;
543 buildAndroid = true;
544 baseArg++;
545 } else if (strcmp(argv[baseArg + 1], "-android") == 0) {
546 platset = true;
547 buildAndroid = true;
548 baseArg++;
549 } else if (strcmp(argv[baseArg + 1], "-windows") == 0) {
550 platset = true;
551 buildWindows = true;
552 baseArg++;
553 } else if (strcmp(argv[baseArg + 1], "-mac") == 0) {
554 platset = true;
555 buildMac = true;
556 baseArg++;
557 } else if (strcmp(argv[baseArg + 1], "-x86") == 0) {
558 buildX86 = true;
559 baseArg++;
560 } else if (strcmp(argv[baseArg + 1], "-x86_64") == 0) {
561 buildAndroid = true;
562 buildX64 = true;
563 baseArg++;
564 } else if (strcmp(argv[baseArg + 1], "-x64") == 0) {
565 buildX64 = true;
566 buildWindows = true;
567 baseArg++;
568 } else if (strcmp(argv[baseArg + 1], "-armeabi-v7a") == 0) {
569 buildV7 = true;
570 buildAndroid = true;
571 platset = true;
572 baseArg++;
573 } else if (strcmp(argv[baseArg + 1], "-arm64-v8a") == 0) {
574 buildV8 = true;
575 buildAndroid = true;
576 platset = true;
577 baseArg++;
578 } else if (strcmp(argv[baseArg + 1], "-extensions") == 0) {
579 baseArg++;
580 if (baseArg + 1 >= argc) {
581 printf("Invalid argument!\n");
582 return 0;
583 }
584 auto exts = std::string_view(argv[baseArg + 1]);
585 while (!exts.empty()) {
586 auto pos = exts.find(';');
587 pos = std::min(pos, exts.size());
588 g_validExts.push_back(exts.substr(0, pos));
589 exts.remove_prefix(std::min(pos + 1, exts.size()));
590 }
591 baseArg++;
592 } else {
593 printf("Invalid argument!\n");
594 return 0;
595 }
596 }
597 if (!platset) {
598 buildWindows = true;
599 buildAndroid = true;
600 buildMac = true;
601 }
602
603 if (argc < baseArg + 3) {
604 printf("invalid args");
605 return 0;
606 }
607
608 inPath = argv[baseArg + 1];
609 } else {
610 printf("Not enough arguments!\n");
611 return 0;
612 }
613 if (argc >= baseArg + 3) {
614 if (argv[baseArg + 2][0] == '/') {
615 roPath = argv[baseArg + 2] + 1;
616 } else {
617 roPath = argv[baseArg + 2];
618 }
619 }
620 if (argc >= baseArg + 5) {
621 g_dataName = argv[baseArg + 3];
622 g_sizeName = argv[baseArg + 4];
623 }
624 if (argc == baseArg + 6) {
625 secName = obj32Name = obj64Name = o32Name = o64Name = x32Name = x64Name = macName = argv[baseArg + 5];
626 obj32Name += "_32.obj";
627 obj64Name += "_64.obj";
628 o32Name += "_32.o";
629 o64Name += "_64.o";
630 x32Name += "_x86.o";
631 x64Name += "_x64.o";
632 macName += "_mac.o";
633 }
634 AddDirectory(inPath, roPath);
635
636 // fix offsets
637 size_t baseOffset = sizeof(FsEntry) * (g_directory.size() + 1);
638 for (auto& d : g_directory) {
639 d.offset += baseOffset;
640 }
641
642 // add terminator
643 g_directory.push_back({ { 0 }, 0, 0 });
644
645 const size_t sizeOfDir = (sizeof(FsEntry) * g_directory.size());
646 const size_t sizeOfData = g_bin.size() + sizeOfDir;
647 auto data = std::make_unique<uint8_t[]>(sizeOfData + sizeof(uint64_t));
648 *reinterpret_cast<uint64_t*>(data.get()) = sizeOfData;
649 std::copy(g_directory.cbegin(), g_directory.cend(), reinterpret_cast<FsEntry*>(data.get() + sizeof(uint64_t)));
650 std::copy(g_bin.cbegin(), g_bin.cend(), data.get() + sizeof(uint64_t) + sizeOfDir);
651 // Build obj
652 if (buildWindows) {
653 if (buildX86) {
654 WriteObj(obj32Name, secName, sizeOfData, data.get(), false);
655 }
656 if (buildX64) {
657 WriteObj(obj64Name, secName, sizeOfData, data.get(), true);
658 }
659 }
660 // Create .elf (.o)
661 if (buildAndroid) {
662 struct {
663 Elf32_Ehdr head{};
664 Elf32_Shdr sections[4]{};
665 Elf32_Sym symbs[3]{};
666 } o32;
667 struct {
668 Elf64_Ehdr head{};
669 Elf64_Shdr sections[4]{};
670 Elf64_Sym symbs[3]{};
671 } o64;
672 if (buildV7) {
673 WriteElf(o32, EM_ARM, o32Name, secName, sizeOfData, data.get());
674 }
675 if (buildV8) {
676 WriteElf(o64, EM_AARCH64, o64Name, secName, sizeOfData, data.get());
677 }
678 if (buildX86) {
679 WriteElf(o32, EM_386, x32Name, secName, sizeOfData, data.get());
680 }
681 if (buildX64) {
682 WriteElf(o64, EM_X86_64, x64Name, secName, sizeOfData, data.get());
683 }
684 }
685 // Create mach-o (.o)
686 if (buildMac) {
687 WriteMacho(macName, secName, sizeOfData, data.get());
688 }
689 }
690