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