Rev 19 | Rev 21 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 19 | Rev 20 | ||
---|---|---|---|
Line 19... | Line 19... | ||
19 | #include <time.h> |
19 | #include <time.h> |
20 | 20 | ||
21 | // platform-specific includes |
21 | // platform-specific includes |
22 | #ifdef _MSC_VER |
22 | #ifdef _MSC_VER |
23 | #include <sys/utime.h> |
23 | #include <sys/utime.h> |
- | 24 | #include <process.h> |
|
24 | #else // !_MSC_VER |
25 | #else // !_MSC_VER |
25 | #include <sys/param.h> |
26 | #include <sys/param.h> |
26 | #include <sys/sysmacros.h> |
27 | #include <sys/sysmacros.h> |
- | 28 | #include <sys/wait.h> |
|
27 | #include <unistd.h> |
29 | #include <unistd.h> |
28 | #include <dirent.h> |
30 | #include <dirent.h> |
29 | #include <utime.h> |
31 | #include <utime.h> |
30 | #endif // _MSC_VER |
32 | #endif // _MSC_VER |
31 | 33 | ||
Line 88... | Line 90... | ||
88 | bool should_follow_symlinks; // follow symlinks |
90 | bool should_follow_symlinks; // follow symlinks |
89 | bool should_autosymlink_dylib; // dynamic libraries should be written under their official SONAME and a named symlink be created pointing at them |
91 | bool should_autosymlink_dylib; // dynamic libraries should be written under their official SONAME and a named symlink be created pointing at them |
90 | bool should_keep_ld_output; // whether to keep .sym files produced by ld calls, togglable by the [+keeplinked] attribute |
92 | bool should_keep_ld_output; // whether to keep .sym files produced by ld calls, togglable by the [+keeplinked] attribute |
91 | bool should_ignore_duplicates; // [+|-dupignore] whether to ignore duplicates |
93 | bool should_ignore_duplicates; // [+|-dupignore] whether to ignore duplicates |
92 | bool should_allow_nonexistent_files; // [+|-optional] whether to continue processing on unexistent files |
94 | bool should_allow_nonexistent_files; // [+|-optional] whether to continue processing on unexistent files |
- | 95 | bool is_bootstrap_file; // entry has the [virtual] attribute |
|
93 | bool is_compiled_bootscript; // entry has [+script] attribute |
96 | bool is_compiled_bootscript; // entry has [+script] attribute |
94 | int extra_ino_flags; // bitmap of extra inode flags (IFS_INO_xxx) |
97 | int extra_ino_flags; // bitmap of extra inode flags (IFS_INO_xxx) |
95 | char *search; // [search=path[:path]] binary search path (the default one will be constructed at startup) |
98 | char *search; // [search=path[:path]] binary search path (the default one will be constructed at startup) |
96 | 99 | ||
97 | 100 | ||
Line 133... | Line 136... | ||
133 | // bootable IFS support |
136 | // bootable IFS support |
134 | static char *bootfile_pathname = NULL; // HACK: pathname to bootcode binary blob file to put at the start of a bootable IFS |
137 | static char *bootfile_pathname = NULL; // HACK: pathname to bootcode binary blob file to put at the start of a bootable IFS |
135 | static size_t bootfile_size = 0; // HACK: size of the bootcode binary blob file to put at the start of a bootable IFS |
138 | static size_t bootfile_size = 0; // HACK: size of the bootcode binary blob file to put at the start of a bootable IFS |
136 | static char *startupfile_pathname = NULL; // HACK: pathname to precompiled startup file blob to put in the startup header of a bootable IFS |
139 | static char *startupfile_pathname = NULL; // HACK: pathname to precompiled startup file blob to put in the startup header of a bootable IFS |
137 | static size_t startupfile_ep_from_imagebase = 0; // HACK: startup code entrypoint offset from image base for a bootable IFS |
140 | static size_t startupfile_ep_from_imagebase = 0; // HACK: startup code entrypoint offset from image base for a bootable IFS |
138 | static char *kernelfile_pathname = NULL; // HACK: pathname to precompiled kernel file blob to put in a bootable IFS |
- | |
139 | static size_t kernelfile_offset = |
141 | static size_t kernelfile_offset = 0x32000; // kernel file offset in the IFS (is it ever supposed to change) |
140 | 142 | ||
141 | 143 | ||
142 | // exported function prototypes |
144 | // exported function prototypes |
143 | int32_t update_checksum (const void *data, const size_t data_len, const bool is_foreign_endianness); // compute an IFS image or startup checksum to store in the trailer |
145 | int32_t update_checksum (const void *data, const size_t data_len, const bool is_foreign_endianness); // compute an IFS image or startup checksum to store in the trailer |
144 | 146 | ||
Line 146... | Line 148... | ||
146 | // prototypes of local functions |
148 | // prototypes of local functions |
147 | static long long read_integer (const char *str); // reads an integer number for a string that may be specified in either hex, octal or decimal base, and may have an optional unit suffix (k, m, g, t) |
149 | static long long read_integer (const char *str); // reads an integer number for a string that may be specified in either hex, octal or decimal base, and may have an optional unit suffix (k, m, g, t) |
148 | static char *resolve_pathname (const char *pathname, const char *search_paths_or_NULL_for_MKIFS_PATH_envvar); // locates pathname among the known search paths and returns a pointer to the resolved pathname (static string) |
150 | static char *resolve_pathname (const char *pathname, const char *search_paths_or_NULL_for_MKIFS_PATH_envvar); // locates pathname among the known search paths and returns a pointer to the resolved pathname (static string) |
149 | static elf_section_header_t *elf_get_section_header_by_name (const elf_header_t *elf, const char *section_name); // get a pointer to a named section header in an ELF file |
151 | static elf_section_header_t *elf_get_section_header_by_name (const elf_header_t *elf, const char *section_name); // get a pointer to a named section header in an ELF file |
150 | static size_t Buffer_WriteIFSDirectoryEntryAt (buffer_t *ifs_data, const size_t write_offset, const fsentry_t *fsentry); // writes the given filesystem entry (without its contents) to the IFS buffer |
152 | static size_t Buffer_WriteIFSDirectoryEntryAt (buffer_t *ifs_data, const size_t write_offset, const fsentry_t *fsentry); // writes the given filesystem entry (without its contents) to the IFS buffer |
151 | static size_t Buffer_AppendIFSFileData (buffer_t *ifs_data, fsentry_t *fsentry); // writes the given filesystem entry's file data (i.e. its contents) to the IFS buffer |
153 | static size_t Buffer_AppendIFSFileData (buffer_t *ifs_data, const fsentry_t *fsentry); // writes the given filesystem entry's file data (i.e. its contents) to the IFS buffer |
152 | static int Buffer_StripELFFile (buffer_t *file, const char **saved_sections, const size_t saved_section_count, const char *indicative_pathname); // strips an ELF file buffer the way mkifs does it and returns whether it succeeded |
154 | static int Buffer_StripELFFile (buffer_t *file, const char **saved_sections, const size_t saved_section_count, const bool should_align_segsize_with_ramsize, const char *indicative_pathname); // strips an ELF file buffer the way mkifs does it and returns whether it succeeded |
153 | static void add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, parms_t *entry_parms, const char *stored_pathname, const char *buildhost_pathname); // stack up a new filesystem entry in the the fsentries array |
155 | static void add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, parms_t *entry_parms, const char *stored_pathname, const char *buildhost_pathname); // stack up a new filesystem entry in the the fsentries array |
154 | static void add_directory_contents_recursively (fsentry_t **fsentries, size_t *fsentry_count, const char *dir_pathname, const size_t start_pathname_len, parms_t *default_parms); // adds the contents of the directory pointed to by dir_pathname to the fsentries array, recursively |
156 | static void add_directory_contents_recursively (fsentry_t **fsentries, size_t *fsentry_count, const char *dir_pathname, const size_t start_pathname_len, parms_t *default_parms); // adds the contents of the directory pointed to by dir_pathname to the fsentries array, recursively |
155 | static int fsentry_compare_pathnames_cb (const void *a, const void *b); // qsort() comparison callback that sorts filesystem entries by pathnames |
157 | static int fsentry_compare_pathnames_cb (const void *a, const void *b); // qsort() comparison callback that sorts filesystem entries by pathnames |
156 | static void parse_line (FILE *buildfile_fp, char *line_buffer, fsentry_t **fsentries, size_t *fsentry_count, parms_t *default_parms); // parses a line in the build file and make the relevant changes to the fsentries array |
158 | static void parse_line (FILE *buildfile_fp, char *line_buffer, fsentry_t **fsentries, size_t *fsentry_count, parms_t *default_parms); // parses a line in the build file and make the relevant changes to the fsentries array |
157 | 159 | ||
Line 448... | Line 450... | ||
448 | 450 | ||
449 | return (count); |
451 | return (count); |
450 | } |
452 | } |
451 | 453 | ||
452 | 454 | ||
453 | static size_t Buffer_AppendIFSFileData (buffer_t *ifs_data, fsentry_t *fsentry) |
455 | static size_t Buffer_AppendIFSFileData (buffer_t *ifs_data, const fsentry_t *fsentry) |
454 | { |
456 | { |
455 | // writes the given filesystem entry's file data (i.e. its contents) to the IFS buffer |
457 | // writes the given filesystem entry's file data (i.e. its contents) to the IFS buffer |
456 | 458 | ||
457 | elf_program_header_t *phdr; |
459 | elf_program_header_t *phdr; |
458 | elf_header_t *elf; |
460 | elf_header_t *elf; |
459 | size_t fixed_physical_addr; |
461 | size_t fixed_physical_addr; |
460 | size_t corrective_offset; |
462 | size_t corrective_offset; |
461 | //size_t segment_type; |
463 | //size_t segment_type; |
462 | size_t |
464 | size_t size_in_memory; |
463 | size_t table_index; |
465 | size_t table_index; |
464 | size_t table_count; |
466 | size_t table_count; |
465 | size_t data_offset; |
467 | size_t data_offset; |
466 | 468 | ||
467 | ASSERT (S_ISREG (fsentry->header.mode), "function called for invalid dirent"); // consistency check |
469 | ASSERT (S_ISREG (fsentry->header.mode), "function called for invalid dirent"); // consistency check |
468 | data_offset = ifs_data->size; // see where we are |
470 | data_offset = ifs_data->size; // see where we are |
469 | 471 | ||
470 | // is the file we're storing a preprocessed ELF file ? |
472 | // is the file we're storing a preprocessed ELF file ? |
471 | if |
473 | if (fsentry->header.ino & IFS_INO_PROCESSED_ELF) |
472 | #ifndef PROCNTO_WIP |
- | |
473 | && (strstr (fsentry->u.file.path, "/procnto-smp-instr") == NULL) |
- | |
474 | #endif // !PROCNTO_WIP |
- | |
475 | ) |
- | |
476 | { |
474 | { |
477 | 475 | ||
478 | elf = (elf_header_t *) fsentry->u.file.UNSAVED_databuf; // quick access to ELF header |
476 | elf = (elf_header_t *) fsentry->u.file.UNSAVED_databuf; // quick access to ELF header |
479 | table_count = ELF_GET_NUMERIC (elf, elf, program_header_table_len); // get the number of program headers |
477 | table_count = ELF_GET_NUMERIC (elf, elf, program_header_table_len); // get the number of program headers |
480 | for (table_index = 0; table_index < table_count; table_index++) |
478 | for (table_index = 0; table_index < table_count; table_index++) |
Line 484... | Line 482... | ||
484 | //if (!((segment_type >= 2) && (segment_type <= 7) || ((segment_type >= 0x6474e550) && (segment_type <= 0x6474e552)) || (segment_type == 0x70000001))) |
482 | //if (!((segment_type >= 2) && (segment_type <= 7) || ((segment_type >= 0x6474e550) && (segment_type <= 0x6474e552)) || (segment_type == 0x70000001))) |
485 | // continue; // NOTE: only certain segments types must be corrected |
483 | // continue; // NOTE: only certain segments types must be corrected |
486 | 484 | ||
487 | 485 | ||
488 | corrective_offset = ELF_GET_NUMERIC (elf, phdr, virtual_addr) - ELF_GET_NUMERIC (elf, phdr, file_offset); |
486 | corrective_offset = ELF_GET_NUMERIC (elf, phdr, virtual_addr) - ELF_GET_NUMERIC (elf, phdr, file_offset); |
489 |
|
487 | size_in_memory = ELF_GET_NUMERIC (elf, phdr, size_in_memory); // get this ELF segment's occupied size in memory |
490 | if ( |
488 | if (size_in_memory != 0) // only patch the physical address of segments that have an actual size in memory |
491 | { |
489 | { |
492 | fixed_physical_addr = ELF_GET_NUMERIC (elf, phdr, physical_addr) + image_base + data_offset - corrective_offset; |
490 | fixed_physical_addr = ELF_GET_NUMERIC (elf, phdr, physical_addr) + image_base + data_offset - corrective_offset; |
493 | ELF_SET_NUMERIC (elf, phdr, physical_addr, fixed_physical_addr); // patch the physical address member of the program header table (NOTE: data_offset is the location where the file data is about to be written) |
491 | ELF_SET_NUMERIC (elf, phdr, physical_addr, fixed_physical_addr); // patch the physical address member of the program header table (NOTE: data_offset is the location where the file data is about to be written) |
494 | } |
492 | } |
495 | } |
493 | } |
Line 514... | Line 512... | ||
514 | } |
512 | } |
515 | return (Buffer_OffsetOf (buffer, occurrence)); // can't fail |
513 | return (Buffer_OffsetOf (buffer, occurrence)); // can't fail |
516 | } |
514 | } |
517 | 515 | ||
518 | 516 | ||
519 | static int Buffer_StripELFFile (buffer_t *file, const char **saved_sections, const size_t saved_section_count, const char *indicative_pathname) |
517 | static int Buffer_StripELFFile (buffer_t *file, const char **saved_sections, const size_t saved_section_count, const bool should_align_segsize_with_ramsize, const char *indicative_pathname) |
520 | { |
518 | { |
521 | // NOTE: for each ELF file, mkifs |
519 | // NOTE: for each ELF file, mkifs |
522 | // -> alters the program header table and offsets each p_addr (physical address) member by <image_base> plus the current file offset (this cannot be done right now, will need to be done once they are known) |
520 | // -> alters the program header table and offsets each p_addr (physical address) member by <image_base> plus the current file offset (this cannot be done right now, will need to be done once they are known) |
523 | // -> throws away and reconstructs the sections table by keeping only the sections that are in the program header, and writes the section table at the start of the first thrown-away section |
521 | // -> throws away and reconstructs the sections table by keeping only the sections that are in the program header, and writes the section table at the start of the first thrown-away section |
524 | // FIXME: what if a thrown away section is located between two program segments ? are they collapsed, moving the segments beyond it one slot down ? |
522 | // FIXME: what if a thrown away section is located between two program segments ? are they collapsed, moving the segments beyond it one slot down ? |
Line 569... | Line 567... | ||
569 | const char *name; |
567 | const char *name; |
570 | elf_section_header_t header; |
568 | elf_section_header_t header; |
571 | buffer_t data; |
569 | buffer_t data; |
572 | } elf_section_t; |
570 | } elf_section_t; |
573 | 571 | ||
574 | const elf_program_header_t *phdr; |
- | |
575 | const elf_section_header_t *shdr; |
572 | const elf_section_header_t *shdr; |
- | 573 | elf_program_header_t *phdr; |
|
- | 574 | elf_program_header_t *other_phdr; |
|
576 | elf_section_t *elf_sections = NULL; // mallocated |
575 | elf_section_t *elf_sections = NULL; // mallocated |
577 | elf_section_t *elf_section = NULL; |
576 | elf_section_t *elf_section = NULL; |
578 | size_t elf_section_count = 0; |
577 | size_t elf_section_count = 0; |
579 | size_t new_shdrtable_offset; |
578 | size_t new_shdrtable_offset; |
580 | size_t new_shdrtable_len; |
579 | size_t new_shdrtable_len; |
581 | size_t sectiondata_start; |
580 | size_t sectiondata_start; |
582 | size_t sectiondata_size; |
581 | size_t sectiondata_size; |
- | 582 | size_t size_in_memory; |
|
- | 583 | size_t size_in_file; |
|
- | 584 | size_t file_offset; |
|
583 | size_t array_index; |
585 | size_t array_index; |
584 | size_t table_index; |
586 | size_t table_index; |
585 | size_t table_count; |
587 | size_t table_count; |
586 | size_t page_size; |
588 | size_t page_size; |
587 | 589 | ||
Line 594... | Line 596... | ||
594 | { |
596 | { |
595 | errno = ENOTSUP; // unsupported architecture: set errno to something meaningful |
597 | errno = ENOTSUP; // unsupported architecture: set errno to something meaningful |
596 | return (0); // and return an error value |
598 | return (0); // and return an error value |
597 | } |
599 | } |
598 | 600 | ||
599 | // |
601 | // if we should align the segment sizes in the ELF file with their occupied memory size (such is the case for e.g. procnto), do that first |
- | 602 | table_count = ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_table_len); // get the number of program headers |
|
- | 603 | for (table_index = 0; table_index < table_count; table_index++) |
|
- | 604 | { |
|
- | 605 | phdr = (elf_program_header_t *) &file->bytes[ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_table_offset) + (size_t) ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_item_size) * table_index]; // quick access to program header |
|
- | 606 | file_offset = ELF_GET_NUMERIC (ELFHDR, phdr, file_offset); // get this ELF segment's start offset in the ELF file |
|
- | 607 | size_in_memory = ELF_GET_NUMERIC (ELFHDR, phdr, size_in_memory); // get this ELF segment's occupied size in memory |
|
- | 608 | size_in_file = ELF_GET_NUMERIC (ELFHDR, phdr, size_in_file); // get this ELF segment's occupied size in the ELF file |
|
- | 609 | if (should_align_segsize_with_ramsize && (size_in_memory != size_in_file)) // should we align this segment's file size with its claimed RAM size ? (such is the case for e.g. procnto) |
|
- | 610 | { |
|
- | 611 | if (size_in_memory > size_in_file) // is it bigger ? if so, make sure we won't be overwriting other segments beyond this one |
|
- | 612 | { |
|
- | 613 | for (array_index = 0; array_index < table_count; array_index++) |
|
- | 614 | { |
|
- | 615 | other_phdr = (elf_program_header_t *) &file->bytes[ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_table_offset) + (size_t) ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_item_size) * array_index]; // quick access to program header |
|
- | 616 | if (other_phdr == phdr) |
|
- | 617 | continue; // skip self |
|
- | 618 | if (ELF_GET_NUMERIC (ELFHDR, other_phdr, file_offset) + ELF_GET_NUMERIC (ELFHDR, other_phdr, size_in_file) < file_offset) |
|
- | 619 | continue; // skip segments that are located before this one |
|
- | 620 | if (ELF_GET_NUMERIC (ELFHDR, other_phdr, file_offset) > file_offset + size_in_memory) |
|
- | 621 | continue; // skip segments that are located after this one, including its corrected size |
|
- | 622 | DIE_WITH_EXITCODE (1, "remapping ELF segment would overwrite segment #%zd in the same file", array_index); |
|
- | 623 | } |
|
- | 624 | ||
- | 625 | // finally, memset() the extra area |
|
- | 626 | Buffer_WriteAt (file, file_offset + size_in_memory, NULL, 0); // reallocate the ELF file data buffer if necessary |
|
- | 627 | memset (&file->bytes[file_offset + size_in_file], 0, size_in_memory - size_in_file); // and write zeroes over the extra space |
|
- | 628 | } |
|
- | 629 | ELF_SET_NUMERIC (ELFHDR, phdr, size_in_file, size_in_memory); // patch this segment's size in the ELF file so that it matches the RAM size |
|
- | 630 | } |
|
- | 631 | } |
|
600 | 632 | ||
- | 633 | // now parse the program header table, and measure the farthest offset known by this table where we'll write the reconstructed section headers table |
|
601 | new_shdrtable_offset = 0; |
634 | new_shdrtable_offset = 0; |
602 | table_count = ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_table_len); |
635 | table_count = ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_table_len); |
603 | for (table_index = 0; table_index < table_count; table_index++) |
636 | for (table_index = 0; table_index < table_count; table_index++) |
604 | { |
637 | { |
605 | phdr = (elf_program_header_t *) &file->bytes[ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_table_offset) + (size_t) ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_item_size) * table_index]; // quick access to program header |
638 | phdr = (elf_program_header_t *) &file->bytes[ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_table_offset) + (size_t) ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_item_size) * table_index]; // quick access to program header |
Line 693... | Line 726... | ||
693 | } |
726 | } |
694 | 727 | ||
695 | 728 | ||
696 | static void add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, parms_t *entry_parms, const char *stored_pathname, const char *buildhost_pathname) |
729 | static void add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, parms_t *entry_parms, const char *stored_pathname, const char *buildhost_pathname) |
697 | { |
730 | { |
- | 731 | #define STRINGARRAY_INIT(string_array) do { (string_array)->args = NULL; (string_array)->count = 0; } while (0) |
|
- | 732 | #define STRINGARRAY_PUSH(string_array,str) do { \ |
|
- | 733 | reallocated_ptr = realloc ((string_array)->args, ((string_array)->count + 1) * sizeof (char *)); \ |
|
- | 734 | ASSERT_WITH_ERRNO (reallocated_ptr); \ |
|
- | 735 | (string_array)->args = reallocated_ptr; \ |
|
- | 736 | (string_array)->args[(string_array)->count] = ((str) != NULL ? strdup ((str)) : NULL); \ |
|
- | 737 | if ((str) != NULL) \ |
|
- | 738 | ASSERT_WITH_ERRNO ((string_array)->args[(string_array)->count]); \ |
|
- | 739 | (string_array)->count++; \ |
|
- | 740 | } while (0) |
|
- | 741 | #define STRINGARRAY_FREE(string_array) do { \ |
|
- | 742 | if ((string_array)->args != NULL) { \ |
|
- | 743 | for (array_index = 0; array_index < (string_array)->count; array_index++) \ |
|
- | 744 | if ((string_array)->args[array_index] != NULL) \ |
|
- | 745 | free ((string_array)->args[array_index]); \ |
|
- | 746 | free ((string_array)->args); \ |
|
- | 747 | (string_array)->args = NULL; \ |
|
- | 748 | } \ |
|
- | 749 | (string_array)->count = 0; \ |
|
- | 750 | } while (0) |
|
- | 751 | ||
- | 752 | typedef struct stringarray_s |
|
- | 753 | { |
|
- | 754 | char **args; |
|
- | 755 | size_t count; |
|
- | 756 | } stringarray_t; |
|
- | 757 | ||
698 | static thread_local char *candidate_pathname = NULL; |
758 | static thread_local char *candidate_pathname = NULL; |
699 | static int inode_count = 0; // will be preincremented each time this function is called |
759 | static int inode_count = 0; // will be preincremented each time this function is called |
700 | 760 | ||
- | 761 | stringarray_t global_argv = { NULL, 0 }; |
|
- | 762 | stringarray_t global_envp = { NULL, 0 }; |
|
- | 763 | stringarray_t line_argv = { NULL, 0 }; |
|
- | 764 | stringarray_t line_envp = { NULL, 0 }; |
|
- | 765 | stringarray_t startup_argv = { NULL, 0 }; |
|
- | 766 | stringarray_t startup_envp = { NULL, 0 }; |
|
- | 767 | stringarray_t procnto_argv = { NULL, 0 }; |
|
- | 768 | stringarray_t procnto_envp = { NULL, 0 }; |
|
- | 769 | stringarray_t linker_argv = { NULL, 0 }; |
|
701 | const char *stored_pathname_without_leading_slash; |
770 | const char *stored_pathname_without_leading_slash; |
702 | const char *original_stored_pathname = NULL; |
771 | const char *original_stored_pathname = NULL; |
- | 772 | buffer_t current_line; |
|
703 | buffer_t *shstrtab = NULL; |
773 | buffer_t *shstrtab = NULL; |
704 | const char *canonical_dylib_name; |
774 | const char *canonical_dylib_name; |
705 | const char *dynamic_strings; // strings table of the ".dynamic" section |
775 | const char *dynamic_strings; // strings table of the ".dynamic" section |
706 | const char *last_dirsep; |
776 | const char *last_dirsep; |
707 |
|
777 | size_t array_index; |
708 | size_t |
778 | size_t line_index; |
709 | size_t fsentry_index; |
779 | size_t fsentry_index; |
710 | char *startup_name = NULL; |
- | |
711 | char *procnto_name = NULL; |
- | |
712 | char *resolved_pathname; |
780 | char *resolved_pathname; |
- | 781 | char *linebit_start; |
|
- | 782 | char *write_ptr; |
|
- | 783 | char *read_ptr; |
|
- | 784 | char *token; |
|
- | 785 | char *value; |
|
- | 786 | char *ctx; |
|
713 | void *reallocated_ptr; |
787 | void *reallocated_ptr; |
714 | void *old_data; |
788 | void *old_data; |
- | 789 | bool is_quoted_context; |
|
- | 790 | bool is_end_of_line; |
|
715 | struct stat stat_buf; |
791 | struct stat stat_buf; |
716 | fsentry_t *fsentry; |
792 | fsentry_t *fsentry; |
717 | int retval; |
793 | int retval; |
718 | 794 | ||
719 | // initial allocation (per thread) |
795 | // initial allocation (per thread) |
Line 727... | Line 803... | ||
727 | { |
803 | { |
728 | LOG_INFO ("directory: ino 0x%x uid %d gid %d mode 0%o path \"%s\"", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname); |
804 | LOG_INFO ("directory: ino 0x%x uid %d gid %d mode 0%o path \"%s\"", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname); |
729 | } |
805 | } |
730 | else if (S_ISREG (entry_parms->st_mode)) // else are we storing a regular file ? |
806 | else if (S_ISREG (entry_parms->st_mode)) // else are we storing a regular file ? |
731 | { |
807 | { |
732 | if ( |
808 | if (entry_parms->is_bootstrap_file) // is it the bootstrap file ? |
733 | { |
809 | { |
734 | // HACK: for now just consider the kernel as a binary blob |
- | |
735 | // FIXME: reimplement properly |
- | |
736 | #ifdef PROCNTO_WIP |
- | |
737 | char *linebit_start; |
- | |
738 | char *content_line; |
- | |
739 | char *write_ptr; |
- | |
740 | char *token; |
- | |
741 | char *value; |
- | |
742 | char *ctx; |
- | |
743 | bool is_quoted_context; |
- | |
744 | bool was_string_split; |
- | |
745 | - | ||
746 | // parse each line of contents |
810 | // parse each line of contents |
747 | ASSERT (entry_parms->data. |
811 | ASSERT (entry_parms->data.size > 0, "kernel specification without inline contents"); |
- | 812 | ||
- | 813 | // parse buffer (non-destructively) line after line |
|
- | 814 | Buffer_Initialize (¤t_line); |
|
748 | for ( |
815 | for (line_index = 0; Buffer_GetNthLine (&entry_parms->data, line_index, ¤t_line); line_index++) |
749 | { |
816 | { |
- | 817 | read_ptr = current_line.bytes; |
|
750 | while (isspace (* |
818 | while (isspace (*read_ptr)) |
751 |
|
819 | read_ptr++; // skip leading spaces |
752 | if ((* |
820 | if ((*read_ptr == '#') || (*read_ptr == 0)) |
753 | continue; // skip comments and empty lines |
821 | continue; // skip comments and empty lines |
754 | 822 | ||
755 | // format of a line: [attributes] [env assignation] [...] [executable] [arg] [...] [comment] |
823 | // format of a line: [attributes] [env assignation] [...] [executable] [arg] [...] [comment] |
756 | // example: "[uid=0 gid=0 perms=0700] CONFIG_PATH=/proc/boot:/etc procnto-smp-instr -v -mr -d 0777 -u 0777" |
824 | // example: "[uid=0 gid=0 perms=0700] CONFIG_PATH=/proc/boot:/etc procnto-smp-instr -v -mr -d 0777 -u 0777" |
- | 825 | ||
757 |
|
826 | LOG_DEBUG ("parsing line: %s", read_ptr); |
758 | 827 | ||
759 | // does this line start with an attribute block ? |
828 | // does this line start with an attribute block ? |
760 | if (* |
829 | if (*read_ptr == '[') |
761 | { |
830 | { |
762 |
|
831 | read_ptr++; // skip the leading square bracket |
763 | linebit_start = |
832 | linebit_start = read_ptr; // remember where it starts |
764 | is_quoted_context = false; // reach the next unescaped closing square bracket that is not between quotes |
833 | is_quoted_context = false; // reach the next unescaped closing square bracket that is not between quotes |
765 | while ((* |
834 | while ((*read_ptr != 0) && !((*read_ptr == ']') && (read_ptr[-1] != '\\') && !is_quoted_context)) |
766 | { |
835 | { |
767 | if (* |
836 | if (*read_ptr == '"') |
768 | is_quoted_context ^= true; // remember when we're between quotes |
837 | is_quoted_context ^= true; // remember when we're between quotes |
769 | else if (!is_quoted_context && (* |
838 | else if (!is_quoted_context && (*read_ptr == ' ')) |
770 | * |
839 | *read_ptr = RECORD_SEP[0]; // turn all spaces outside quoted contexts into an ASCII record separator to ease token splitting |
771 |
|
840 | read_ptr++; // reach the next unescaped closing square bracket |
772 | } |
841 | } |
773 | if (* |
842 | if (*read_ptr != ']') |
774 | { |
843 | { |
775 | LOG ("warning", 0, "syntax error in \"%s\" line %d: unterminated attributes block (skipping)", buildfile_pathname, lineno); |
844 | LOG ("warning", 0, "syntax error in \"%s\" line %d: unterminated attributes block (skipping)", buildfile_pathname, lineno); |
776 | continue; // invalid attribute block, skip line |
845 | continue; // invalid attribute block, skip line |
777 | } |
846 | } |
- | 847 | is_end_of_line = (*read_ptr == 0); // see if we're at the end of line already |
|
778 | * |
848 | *read_ptr = 0; // end the attribute block in all cases so that it is a parsable C string |
779 | 849 | ||
780 | // now parse the attribute tokens (NOTE: THE LIST OF ALLOWED ATTRIBUTES HERE IS NOT DOCUMENTED) |
850 | // now parse the attribute tokens (NOTE: THE LIST OF ALLOWED ATTRIBUTES HERE IS NOT DOCUMENTED) |
781 | token = strtok_r (linebit_start, RECORD_SEP, &ctx); |
851 | token = strtok_r (linebit_start, RECORD_SEP, &ctx); |
782 | while (token != NULL) |
852 | while (token != NULL) |
783 | { |
853 | { |
784 | #define REACH_TOKEN_VALUE() do { value = strchr (token, '=') + 1; if (*value == '"') value++; } while (0) |
854 | #define REACH_TOKEN_VALUE() do { value = strchr (token, '=') + 1; if (*value == '"') value++; } while (0) |
785 | if (false) |
855 | if (false) {} |
786 | else if (strncmp (token, "prefix=", 7) == 0) { REACH_TOKEN_VALUE (); entry_parms->prefix = (*value == '/' ? value + 1 : value); } // skip possible leading slash in prefix (NOTE: stolen pointer. Do not free.) |
856 | else if (strncmp (token, "prefix=", 7) == 0) { REACH_TOKEN_VALUE (); entry_parms->prefix = (*value == '/' ? value + 1 : value); } // skip possible leading slash in prefix (NOTE: stolen pointer. Do not free.) |
787 | else if (strncmp (token, "uid=", 4) == 0) { REACH_TOKEN_VALUE (); entry_parms->uid = (int) read_integer (value); } |
857 | else if (strncmp (token, "uid=", 4) == 0) { REACH_TOKEN_VALUE (); entry_parms->uid = (int) read_integer (value); } |
788 | else if (strncmp (token, "gid=", 4) == 0) { REACH_TOKEN_VALUE (); entry_parms->gid = (int) read_integer (value); } |
858 | else if (strncmp (token, "gid=", 4) == 0) { REACH_TOKEN_VALUE (); entry_parms->gid = (int) read_integer (value); } |
789 | else if (strncmp (token, "perms=", 6) == 0) { REACH_TOKEN_VALUE (); entry_parms->perms = (int) read_integer (value); } |
859 | else if (strncmp (token, "perms=", 6) == 0) { REACH_TOKEN_VALUE (); entry_parms->perms = (int) read_integer (value); } |
790 | else if (strcmp (token, "+followlink") == 0) entry_parms->should_follow_symlinks = true; |
860 | else if (strcmp (token, "+followlink") == 0) entry_parms->should_follow_symlinks = true; |
Line 794... | Line 864... | ||
794 | else LOG_WARNING ("unimplemented bootstrap executable attribute in \"%s\" line %d: '%s'", buildfile_pathname, lineno, token); |
864 | else LOG_WARNING ("unimplemented bootstrap executable attribute in \"%s\" line %d: '%s'", buildfile_pathname, lineno, token); |
795 | #undef REACH_TOKEN_VALUE |
865 | #undef REACH_TOKEN_VALUE |
796 | token = strtok_r (NULL, RECORD_SEP, &ctx); // proceed to next attribute token |
866 | token = strtok_r (NULL, RECORD_SEP, &ctx); // proceed to next attribute token |
797 | } |
867 | } |
798 | 868 | ||
799 |
|
869 | if (is_end_of_line) |
800 |
|
870 | continue; // if end of line was reached, proceed to the next line |
801 |
|
871 | else |
- | 872 | read_ptr++; // else reach the next character (after the NUL split) and continue processing the same line |
|
802 | } // end of "this line starts with an attributes block" |
873 | } // end of "this line starts with an attributes block" |
803 | 874 | ||
- | 875 | // at this point we are past the attributes block |
|
- | 876 | ||
- | 877 | // reset contextual argv/envp arrays |
|
- | 878 | line_argv.args = NULL; |
|
- | 879 | line_argv.count = 0; |
|
- | 880 | line_envp.args = NULL; |
|
- | 881 | line_envp.count = 0; |
|
- | 882 | ||
804 | // |
883 | // now read each word (or quoted group of words), unescaping escaped characters |
805 | while (* |
884 | while (*read_ptr != 0) |
806 | { |
885 | { |
- | 886 | while ((*read_ptr != 0) && isspace (*read_ptr)) |
|
- | 887 | read_ptr++; // skip intermediate spaces and reach the next word |
|
- | 888 | ||
- | 889 | if (*read_ptr == '#') |
|
- | 890 | break; // if the rest of the line is commented out, stop parsing it and proceed to the next line |
|
- | 891 | ||
807 | linebit_start = |
892 | linebit_start = read_ptr; // remember the word (or quoted group of words) starts here |
808 | write_ptr = |
893 | write_ptr = read_ptr; |
809 | is_quoted_context = (* |
894 | is_quoted_context = (*read_ptr == '"'); // see if we're entering a quoted context or not |
810 | if (is_quoted_context) |
895 | if (is_quoted_context) |
811 |
|
896 | read_ptr++; // skip a possible initial quote in the word |
812 | while ((* |
897 | while ((*read_ptr != 0) && ((!is_quoted_context && !isspace (*read_ptr)) || (is_quoted_context && (*read_ptr == '"')))) |
813 | { |
898 | { |
814 | if (* |
899 | if (*read_ptr == '\\') |
815 | { |
- | |
816 | content_line++; |
- | |
817 |
|
900 | read_ptr++; // unescape characters that are escaped with '\' by advancing the read pointer |
818 | } |
- | |
819 | else |
- | |
820 |
|
901 | *write_ptr++ = *read_ptr++; // recopy characters as we read them |
821 | content_line++; |
- | |
822 | } |
902 | } |
- | 903 | is_end_of_line = (*read_ptr == 0); // see if we're at the end of line already |
|
- | 904 | *write_ptr = 0; // stop the rewritten string here |
|
823 | 905 | ||
824 | // we reached a closing quote, a space OR an equal sign |
- | |
825 | if (*content_line == '=') |
- | |
826 | { |
- | |
827 | // it's an environment variable assignation |
- | |
828 | *write_ptr++ = *content_line++; // skip the equal sign |
- | |
829 | is_quoted_context = (*content_line == '"'); |
- | |
830 | if (is_quoted_context) |
- | |
831 | content_line++; // skip a possible initial quote in the value |
- | |
832 |
|
906 | // end of word, i.e. we reached either a closing quote or a space. The string bit has been rewritted at linebit_start without quotes and with characters unescaped. |
833 | { |
- | |
834 | if (*content_line == '\\') |
- | |
835 | { |
- | |
836 | content_line++; |
- | |
837 | *write_ptr++ = *content_line; // unescape characters that are escaped with '\' |
- | |
838 | } |
- | |
839 | else |
- | |
840 | *write_ptr++ = *content_line; |
- | |
841 | content_line++; |
- | |
842 | } |
- | |
843 | if (*write_ptr != 0) |
- | |
844 | { |
- | |
845 | *write_ptr = 0; // terminate the string if necessary |
- | |
846 | was_string_split = true; |
- | |
847 | } |
- | |
848 | else |
- | |
849 | was_string_split = false; |
- | |
850 | if (is_quoted_context && (*content_line == '"')) |
- | |
851 | content_line++; // skip a possible final quote |
- | |
852 | while ((*content_line != 0) && isspace (*content_line)) |
- | |
853 | content_line++; // skip spaces |
- | |
854 | 907 | ||
- | 908 | if ((strchr (linebit_start, '=') != NULL) && (line_argv.count == 0)) // is it an assignation AND have we not started constructing argv yet? |
|
- | 909 | { |
|
- | 910 | STRINGARRAY_PUSH (&line_envp, linebit_start); // linebit_start is of the form "NAME=VALUE": it's an environment variable assignation |
|
- | 911 | LOG_DEBUG ("collected envp: [%s]", linebit_start); |
|
- | 912 | } |
|
855 |
|
913 | else // it's an executable argument (argv) |
- | 914 | { |
|
- | 915 | STRINGARRAY_PUSH (&line_argv, linebit_start); // linebit_start is either NOT of the form "NAME=VALUE" OR we started constructing argv: it's a command-line argument |
|
856 | LOG_DEBUG (" |
916 | LOG_DEBUG ("collected argv: [%s]", linebit_start); |
- | 917 | } |
|
857 | 918 | ||
- | 919 | if (!is_end_of_line) |
|
- | 920 | read_ptr++; // if we haven't reach the end of the line yet, advance to the next character (after the NUL split) |
|
858 |
|
921 | } // end while (*read_ptr != 0) |
859 | 922 | ||
860 |
|
923 | // we finished parsing the line |
861 | 924 | ||
- | 925 | // did we fill an executable argv? As per QNX docs, the first executable must be startup-*, the last executable must be procnto. |
|
- | 926 | if (line_argv.count > 0) |
|
- | 927 | { |
|
862 |
|
928 | if (startup_argv.args == NULL) |
- | 929 | { |
|
863 |
|
930 | startup_argv.args = line_argv.args; // relocate these pointers to the right place |
864 |
|
931 | startup_argv.count = line_argv.count; |
- | 932 | startup_envp.args = line_envp.args; // relocate these pointers to the right place |
|
865 |
|
933 | startup_envp.count = line_envp.count; |
866 | } |
934 | } |
867 | else |
935 | else |
868 | { |
936 | { |
869 | *write_ptr = 0; // terminate the string |
- | |
870 | if (is_quoted_context && (*content_line == '"')) |
- | |
871 | content_line++; // skip a possible final quote |
- | |
872 | - | ||
873 | LOG_DEBUG ("exe name: [%s]", linebit_start); |
- | |
874 | - | ||
875 | while ((*content_line != 0) && isspace (*content_line)) |
- | |
876 | content_line++; // skip leading spaces |
- | |
877 | - | ||
878 | // |
937 | STRINGARRAY_FREE (&procnto_argv); // if procnto's argv was already assigned, free the previous array as we'll be replacing it with a new one |
879 | if (startup_name == NULL) |
- | |
880 |
|
938 | procnto_argv.args = line_argv.args; // relocate these pointers to the right place |
881 | else |
- | |
882 | { |
- | |
883 | if (procnto_name != NULL) |
- | |
884 | free (procnto_name); |
- | |
885 |
|
939 | procnto_argv.count = line_argv.count; |
886 | } |
- | |
887 | - | ||
888 | if ((*content_line == '#') || (*content_line == 0)) |
- | |
889 |
|
940 | STRINGARRAY_FREE (&procnto_envp); // if procnto's envp was already assigned, free the previous array as we'll be replacing it with a new one |
890 | - | ||
891 | // what comes after now must be optional arguments |
- | |
892 |
|
941 | procnto_envp.args = line_envp.args; // relocate these pointers to the right place |
893 |
|
942 | procnto_envp.count = line_envp.count; |
894 | - | ||
895 | // FIXME: parse executable command-line arguments |
- | |
896 | - | ||
897 | break; // stop parsing once all the arguments have been read |
- | |
898 | } |
943 | } |
- | 944 | line_argv.args = NULL; // void the line_argv array so as to not free it as we stole its args pointers |
|
- | 945 | line_argv.count = 0; |
|
- | 946 | line_envp.args = NULL; // void the line_envp array so as to not free it as we stole its args pointers |
|
- | 947 | line_envp.count = 0; |
|
899 | } |
948 | } |
- | 949 | else // this line contained no executable invokation, so stack up its envp assignations into the global envp array |
|
- | 950 | for (array_index = 0; array_index < line_envp.count; array_index++) |
|
- | 951 | STRINGARRAY_PUSH (&global_envp, line_envp.args[array_index]); |
|
- | 952 | ||
- | 953 | // release the contextual argv/envp arrays |
|
900 |
|
954 | STRINGARRAY_FREE (&line_argv); |
- | 955 | STRINGARRAY_FREE (&line_envp); |
|
- | 956 | ||
- | 957 | } // end for (line_index = 0; Buffer_GetNthLine (&entry_parms->data, line_index, ¤t_line); line_index++) |
|
901 | free (entry_parms->data.bytes); // free the inline specification once it's parsed |
958 | free (entry_parms->data.bytes); // free the inline specification once it's parsed |
902 | entry_parms->data.bytes = NULL; |
959 | entry_parms->data.bytes = NULL; |
903 | entry_parms->data. |
960 | entry_parms->data.size = 0; |
904 | 961 | ||
905 | ASSERT ( |
962 | ASSERT (startup_argv.args && startup_argv.args[0] && *startup_argv.args[0], "the QNX startup executable (startup-*) is missing in this bootstrap inline specification"); |
906 | ASSERT ( |
963 | ASSERT (procnto_argv.args && procnto_argv.args[0] && *procnto_argv.args[0], "the QNX kernel (procnto-*) is missing in this bootstrap inline specification"); |
907 | 964 | ||
908 | // now we know which startup and procnto executables to use |
965 | // now we know which startup and procnto executables to use |
909 | LOG_DEBUG ("Startup: %s", |
966 | LOG_DEBUG ("Startup: %s", startup_argv.args[0]); |
910 | LOG_DEBUG ("Kernel: %s", |
967 | LOG_DEBUG ("Kernel: %s", procnto_argv.args[0]); |
911 | - | ||
912 | sprintf (candidate_pathname, "%s/%s", (entry_parms->prefix != NULL ? entry_parms->prefix : ""), procnto_name); // fix the entry name |
- | |
913 | stored_pathname = candidate_pathname; |
- | |
914 | entry_parms->extra_ino_flags |= /*IFS_INO_PROCESSED_ELF | */IFS_INO_BOOTSTRAP_EXE; // procnto needs to have these flags stamped on the inode |
- | |
915 | entry_parms->st_mode = S_IFREG | entry_parms->perms; // apply specified procnto permissions |
- | |
916 | image_kernel_ino = entry_parms->extra_ino_flags | (inode_count + 1); |
- | |
917 | 968 | ||
918 | static thread_local char linker_pathname[MAXPATHLEN] = ""; |
969 | static thread_local char linker_pathname[MAXPATHLEN] = ""; |
919 | static thread_local char linker_sysroot_arg[MAXPATHLEN] = ""; |
970 | static thread_local char linker_sysroot_arg[MAXPATHLEN] = ""; |
920 | static thread_local char linker_script_pathname_arg[MAXPATHLEN] = ""; |
971 | static thread_local char linker_script_pathname_arg[MAXPATHLEN] = ""; |
921 | static thread_local char procnto_buildhost_pathname[MAXPATHLEN] = ""; |
972 | static thread_local char procnto_buildhost_pathname[MAXPATHLEN] = ""; |
922 | static thread_local char procnto_sym_filename[MAXPATHLEN] = ""; |
973 | static thread_local char procnto_sym_filename[MAXPATHLEN] = ""; |
- | 974 | buffer_t bootargs_buffer = { 0 }; |
|
- | 975 | char *bootargs_location; |
|
923 | 976 | ||
924 | // construct the arguments that are based on environment variables (infer QNX_HOST from QNX_TARGET) |
977 | // construct the arguments that are based on environment variables (infer QNX_HOST from QNX_TARGET) |
925 | #if defined(_WIN32) |
978 | #if defined(_WIN32) |
926 |
|
979 | sprintf_s (linker_pathname, sizeof (linker_pathname), "%s/../../host/win64/x86_64/usr/bin/%s-ld.exe", QNX_TARGET, (strcmp (image_processor, "x86_64") == 0 ? "x86_64-pc-nto-qnx8.0.0" : "aarch64-unknown-nto-qnx8.0.0")); // Win32: note the .exe extension |
927 | #elif defined(__linux__) |
980 | #elif defined(__linux__) |
928 |
|
981 | sprintf_s (linker_pathname, sizeof (linker_pathname), "%s/../../host/linux/x86_64/usr/bin/%s-ld", QNX_TARGET, (strcmp (image_processor, "x86_64") == 0 ? "x86_64-pc-nto-qnx8.0.0" : "aarch64-unknown-nto-qnx8.0.0")); |
929 | #elif defined(__QNXNTO__) |
982 | #elif defined(__QNXNTO__) |
930 |
|
983 | sprintf_s (linker_pathname, sizeof (linker_pathname), "%s/../../host/qnx8/x86_64/usr/bin/%s-ld", QNX_TARGET, (strcmp (image_processor, "x86_64") == 0 ? "x86_64-pc-nto-qnx8.0.0" : "aarch64-unknown-nto-qnx8.0.0")); |
931 | #else // wtf are you building this on? |
984 | #else // wtf are you building this on? |
932 | #error Please port the GNU linker x86_64-pc-nto-qnx8.0.0-ld and aarch64-unknown-nto-qnx8.0.0-ld to your host architecture first before compiling ifstool. |
985 | #error Please port the GNU linker x86_64-pc-nto-qnx8.0.0-ld and aarch64-unknown-nto-qnx8.0.0-ld to your host architecture first before compiling ifstool. |
933 | #endif |
986 | #endif |
934 | ASSERT (access (linker_pathname, 0) == 0, "host cross-linker for QNX8 \"%s\" not found", linker_pathname); |
987 | ASSERT (access (linker_pathname, 0) == 0, "host cross-linker for QNX8 \"%s\" not found", linker_pathname); |
935 |
|
988 | sprintf_s (linker_sysroot_arg, sizeof (linker_sysroot_arg), "--sysroot=%s/%s/", QNX_TARGET, image_processor); |
936 |
|
989 | sprintf_s (linker_script_pathname_arg, sizeof (linker_script_pathname_arg), "-T%s/%s/lib/nto.link", QNX_TARGET, image_processor); |
937 | 990 | ||
938 | resolved_pathname = resolve_pathname ( |
991 | resolved_pathname = resolve_pathname (procnto_argv.args[0], entry_parms->search); // locate the procnto kernel location |
939 | ASSERT (resolved_pathname, "QNX kernel \"%s\" not found in search path", |
992 | ASSERT (resolved_pathname, "QNX kernel \"%s\" not found in search path", procnto_argv.args[0]); |
940 |
|
993 | strcpy_s (procnto_buildhost_pathname, sizeof (procnto_buildhost_pathname), resolved_pathname); |
941 | 994 | ||
942 | sprintf_s (procnto_sym_filename, sizeof (procnto_sym_filename), "%s.sym%s", |
995 | sprintf_s (procnto_sym_filename, sizeof (procnto_sym_filename), "%s.sym%s", procnto_argv.args[0], sym_suffix); |
943 | 996 | ||
944 |
|
997 | // construct the linker invokation command-line arguments array (argv) |
945 | |
998 | STRINGARRAY_INIT (&linker_argv); |
946 |
|
999 | STRINGARRAY_PUSH (&linker_argv, strrchr (linker_pathname, '/') + 1); // "${TARGET_TRIPLE}-ld" |
947 |
|
1000 | STRINGARRAY_PUSH (&linker_argv, linker_sysroot_arg); // "--sysroot=${QNX_TARGET}/${TARGET_CPU}/" |
948 |
|
1001 | STRINGARRAY_PUSH (&linker_argv, linker_script_pathname_arg); // "-T${QNX_TARGET}/${TARGET_CPU}/lib/nto.link" |
949 |
|
1002 | STRINGARRAY_PUSH (&linker_argv, "--section-start"); |
950 |
|
1003 | STRINGARRAY_PUSH (&linker_argv, ".text=0xffff800000001000"); |
951 |
|
1004 | STRINGARRAY_PUSH (&linker_argv, "--no-relax"); |
952 |
|
1005 | STRINGARRAY_PUSH (&linker_argv, procnto_buildhost_pathname); // "${QNX_TARGET}/${TARGET_CPU}/boot/sys/procnto-smp-instr" |
953 |
|
1006 | STRINGARRAY_PUSH (&linker_argv, "-o"); |
954 |
|
1007 | STRINGARRAY_PUSH (&linker_argv, procnto_sym_filename); // "procnto-smp-instr.sym" |
955 |
|
1008 | STRINGARRAY_PUSH (&linker_argv, NULL); // don't forget to terminate the argv array with a NULL pointer |
956 | }; |
- | |
957 | if (verbose_level > 2) |
1009 | if (verbose_level > 2) |
958 | { |
1010 | { |
959 | fprintf (stderr, "ifstool: calling:"); |
1011 | fprintf (stderr, "ifstool: calling:"); |
960 | for ( |
1012 | for (array_index = 0; array_index < linker_argv.count - 1; array_index++) |
961 | fprintf (stderr, " '%s'", linker_argv[ |
1013 | fprintf (stderr, " '%s'", linker_argv.args[array_index]); |
962 | fputc ('\n', stderr); |
1014 | fputc ('\n', stderr); |
963 | } |
1015 | } |
- | 1016 | #ifdef _WIN32 |
|
964 | _spawnv (_P_WAIT, linker_pathname, linker_argv); // spawn the linker and produce a stripped procnto (wait for completion) |
1017 | _spawnv (_P_WAIT, linker_pathname, linker_argv.args); // spawn the linker and produce a stripped procnto (wait for completion) |
- | 1018 | #else // !_WIN32, thus POSIX |
|
- | 1019 | do { |
|
- | 1020 | int status; |
|
- | 1021 | pid_t pid = fork (); // duplicate ourselves so as to create a new process |
|
- | 1022 | ASSERT_WITH_ERRNO (pid != -1); |
|
- | 1023 | if (pid == 0) |
|
- | 1024 | { |
|
- | 1025 | execv (linker_pathname, linker_argv); // spawn the child process |
|
- | 1026 | DIE_WITH_EXITCODE (1, "execve() failed"); // exec never returns |
|
- | 1027 | } |
|
- | 1028 | else |
|
- | 1029 | waitpid (pid, &status, 0); // wait for the child to finish |
|
- | 1030 | } while (0); |
|
- | 1031 | #endif // _WIN32 |
|
- | 1032 | STRINGARRAY_FREE (&linker_argv); |
|
965 | if (!Buffer_ReadFromFile (&entry_parms->data, procnto_sym_filename)) // load the output file |
1033 | if (!Buffer_ReadFromFile (&entry_parms->data, procnto_sym_filename)) // load the output file |
966 | DIE_WITH_EXITCODE (1, "the host cross-linker failed to produce a readable stripped \"%s\" kernel: %s", procnto_sym_filename, strerror (errno)); |
1034 | DIE_WITH_EXITCODE (1, "the host cross-linker failed to produce a readable stripped \"%s\" kernel: %s", procnto_sym_filename, strerror (errno)); |
967 | if (!entry_parms->should_keep_ld_output) |
1035 | if (!entry_parms->should_keep_ld_output) |
968 | unlink (procnto_sym_filename); // remove the linker output file if we want to |
1036 | unlink (procnto_sym_filename); // remove the linker output file if we want to |
- | 1037 | ||
- | 1038 | // save the boot arguments. The magic to look for is "ddpvbskr" -- whatever that means |
|
- | 1039 | if ((bootargs_location = Buffer_FindFirstByteArray (&entry_parms->data, "ddpvbskr")) == NULL) |
|
- | 1040 | DIE_WITH_EXITCODE (1, "unable to find boot args location in the stripped \"%s\" kernel", stored_pathname); |
|
- | 1041 | Buffer_InitWithSize (&bootargs_buffer, sizeof (bootargs_entry_t)); // prepare a boot args entry |
|
- | 1042 | ((bootargs_entry_t *) bootargs_buffer.bytes)->argc = (uint8_t) procnto_argv.count; |
|
- | 1043 | ((bootargs_entry_t *) bootargs_buffer.bytes)->envc = (uint8_t) (global_envp.count + procnto_envp.count); |
|
- | 1044 | ((bootargs_entry_t *) bootargs_buffer.bytes)->shdr_addr = (uint32_t) (image_base + bootfile_size); // same value as startup_header.image_paddr (which is not set yet) (TODO: support 64-bit shdr_addr offsets -- see comment in bootargs_entry_t struct) |
|
- | 1045 | for (array_index = 0; array_index < procnto_argv.count; array_index++) |
|
- | 1046 | ASSERT_WITH_ERRNO (Buffer_Append (&bootargs_buffer, procnto_argv.args[array_index], strlen (procnto_argv.args[array_index]) + 1)); // append string including NUL terminator |
|
- | 1047 | for (array_index = 0; array_index < global_envp.count; array_index++) |
|
- | 1048 | ASSERT_WITH_ERRNO (Buffer_Append (&bootargs_buffer, global_envp.args[array_index], strlen (global_envp.args[array_index]) + 1)); // append string including NUL terminator |
|
- | 1049 | for (array_index = 0; array_index < procnto_envp.count; array_index++) |
|
- | 1050 | ASSERT_WITH_ERRNO (Buffer_Append (&bootargs_buffer, procnto_envp.args[array_index], strlen (procnto_envp.args[array_index]) + 1)); // append string including NUL terminator |
|
- | 1051 | ((bootargs_entry_t *) bootargs_buffer.bytes)->size_hi = (uint8_t) ((bootargs_buffer.size >> 8) & 0xff); |
|
- | 1052 | ((bootargs_entry_t *) bootargs_buffer.bytes)->size_lo = (uint8_t) ((bootargs_buffer.size >> 0) & 0xff); |
|
- | 1053 | ASSERT_WITH_ERRNO (Buffer_WriteBufferAt (&entry_parms->data, (size_t) bootargs_location - (size_t) entry_parms->data.bytes, &bootargs_buffer)); |
|
- | 1054 | Buffer_Forget (&bootargs_buffer); // release the boot args buffer once it's written |
|
969 | 1055 | ||
970 | // now strip this prelinked ELF kernel file |
1056 | // now strip this prelinked ELF kernel file |
971 | Buffer_StripELFFile (&entry_parms->data, (const char **) saved_ELF_sections, 1, stored_pathname); // strip the ELF file as per QNX docs (only keep ONE section, which is "QNX_info") |
1057 | ASSERT_WITH_ERRNO (Buffer_StripELFFile (&entry_parms->data, (const char **) saved_ELF_sections, 1, true, stored_pathname)); // strip the ELF file as per QNX docs (only keep ONE section, which is "QNX_info", and align the segment size in file with the size it occupies in memory) |
- | 1058 | ||
- | 1059 | sprintf_s (candidate_pathname, MAXPATHLEN, "%s/%s", (entry_parms->prefix != NULL ? entry_parms->prefix : ""), procnto_argv.args[0]); // fix the entry name |
|
- | 1060 | stored_pathname = candidate_pathname; |
|
- | 1061 | ||
972 | entry_parms->extra_ino_flags |= IFS_INO_PROCESSED_ELF; // mark this inode as a preprocessed ELF file |
1062 | entry_parms->extra_ino_flags |= IFS_INO_PROCESSED_ELF | IFS_INO_BOOTSTRAP_EXE; // mark this inode as a preprocessed *bootstrap* ELF file |
- | 1063 | entry_parms->st_mode = S_IFREG | entry_parms->perms; // procnto is a regular file |
|
- | 1064 | image_kernel_ino = entry_parms->extra_ino_flags | (inode_count + 1); |
|
973 | 1065 | ||
974 | #else // !PROCNTO_WIP |
- | |
975 | /* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK */ |
- | |
976 | /* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK */ |
- | |
977 | /* HACK */ |
- | |
978 | /* HACK */ sprintf_s (candidate_pathname, MAXPATHLEN, "%s/procnto-smp-instr", (entry_parms->prefix != NULL ? entry_parms->prefix : "")); // HACK: fix the entry name |
- | |
979 | /* HACK */ stored_pathname = candidate_pathname; |
- | |
980 | /* HACK */ entry_parms->extra_ino_flags |= IFS_INO_PROCESSED_ELF | IFS_INO_BOOTSTRAP_EXE; // procnto needs to have these flags stamped on the inode |
- | |
981 |
|
1066 | STRINGARRAY_FREE (&procnto_argv); // release procnto's argv array |
982 | /* HACK */ image_kernel_ino = entry_parms->extra_ino_flags | (inode_count + 1); |
- | |
983 |
|
1067 | STRINGARRAY_FREE (&procnto_envp); // release procnto's envp array |
984 |
|
1068 | STRINGARRAY_FREE (&global_envp); // release the global envp array |
985 | /* HACK */ if (!Buffer_ReadFromFile (&entry_parms->data, kernelfile_pathname)) // read kernel file as a precompiled binary blob |
- | |
986 | /* HACK */ { |
- | |
987 | /* HACK */ fprintf (stderr, "fatal error: unable to read precompiled kernel file \"%s\" specified in --kernelfile argument\n", kernelfile_pathname); |
- | |
988 | /* HACK */ exit (1); |
- | |
989 | /* HACK */ } |
- | |
990 | /* HACK */ |
- | |
991 | /* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK */ |
- | |
992 | /* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK */ |
- | |
993 | #endif // PROCNTO_WIP |
- | |
994 | } |
1069 | } |
995 | else if (entry_parms->is_compiled_bootscript) // else is it a startup script ? |
1070 | else if (entry_parms->is_compiled_bootscript) // else is it a startup script ? |
996 | image_bootscript_ino = inode_count + 1; // save boot script inode number for image header |
1071 | image_bootscript_ino = inode_count + 1; // save boot script inode number for image header |
997 | 1072 | ||
998 | // do we already know the data for this data blob ? |
1073 | // do we already know the data for this data blob ? |
Line 1065... | Line 1140... | ||
1065 | } // end if the file we're storing is a dylib |
1140 | } // end if the file we're storing is a dylib |
1066 | 1141 | ||
1067 | // now strip this ELF file if necessary |
1142 | // now strip this ELF file if necessary |
1068 | if (!(entry_parms->extra_ino_flags & IFS_INO_PROCESSED_ELF)) |
1143 | if (!(entry_parms->extra_ino_flags & IFS_INO_PROCESSED_ELF)) |
1069 | { |
1144 | { |
1070 | Buffer_StripELFFile (&entry_parms->data, (const char **) saved_ELF_sections, saved_ELF_section_count, stored_pathname); // strip the ELF file à la mkifs |
1145 | Buffer_StripELFFile (&entry_parms->data, (const char **) saved_ELF_sections, saved_ELF_section_count, false, stored_pathname); // strip the ELF file à la mkifs |
1071 | entry_parms->extra_ino_flags |= IFS_INO_PROCESSED_ELF; // mark this inode as a preprocessed ELF file |
1146 | entry_parms->extra_ino_flags |= IFS_INO_PROCESSED_ELF; // mark this inode as a preprocessed ELF file |
1072 | } // end if the file is not yet a processed ELF |
1147 | } // end if the file is not yet a processed ELF |
1073 | } // end if the file we're storing is an ELF file |
1148 | } // end if the file we're storing is an ELF file |
1074 | #undef ELFHDR // undefine the macro that used to always point to the ELF header at the beginning of the file |
1149 | #undef ELFHDR // undefine the macro that used to always point to the ELF header at the beginning of the file |
1075 | } |
1150 | } |
Line 1357... | Line 1432... | ||
1357 | if ((sep = strchr (value, '=')) != NULL) image_totalsize = (uint32_t) read_integer (sep + 1); // if we have an equal sign, read optional image padding size |
1432 | if ((sep = strchr (value, '=')) != NULL) image_totalsize = (uint32_t) read_integer (sep + 1); // if we have an equal sign, read optional image padding size |
1358 | if ((sep = strchr (value, '%')) != NULL) image_align = (uint32_t) read_integer (sep + 1); // if we have a modulo sign, read optional image aligmnent |
1433 | if ((sep = strchr (value, '%')) != NULL) image_align = (uint32_t) read_integer (sep + 1); // if we have a modulo sign, read optional image aligmnent |
1359 | LOG_INFO ("image 0x%x-0x%x maxsize %d totalsize %d align %d", image_base, image_end, image_maxsize, image_totalsize, image_align); |
1434 | LOG_INFO ("image 0x%x-0x%x maxsize %d totalsize %d align %d", image_base, image_end, image_maxsize, image_totalsize, image_align); |
1360 | } |
1435 | } |
1361 | else if (strncmp (token, "virtual=", 8) == 0) { REACH_TOKEN_VALUE (); |
1436 | else if (strncmp (token, "virtual=", 8) == 0) { REACH_TOKEN_VALUE (); |
1362 | if ((bootfile_pathname == NULL) || (startupfile_pathname |
1437 | if ((bootfile_pathname == NULL) || (startupfile_pathname == NULL)) // HACK until I figure out how to re-create them |
1363 | DIE_WITH_EXITCODE (1, "creating bootable images require the --bootfile, --startupfile and --kernelfile command-line options in \"%s\" line %d", buildfile_pathname, lineno); |
1438 | DIE_WITH_EXITCODE (1, "creating bootable images require the --bootfile, --startupfile and --kernelfile command-line options in \"%s\" line %d", buildfile_pathname, lineno); |
1364 | if ((sep = strchr (value, ',')) != NULL) // do we have a comma separating (optional) processor and boot file name ? |
1439 | if ((sep = strchr (value, ',')) != NULL) // do we have a comma separating (optional) processor and boot file name ? |
1365 | { |
1440 | { |
1366 | *sep = 0; |
1441 | *sep = 0; |
1367 | strcpy_s (image_processor, sizeof (image_processor), value); // save processor |
1442 | strcpy_s (image_processor, sizeof (image_processor), value); // save processor |
Line 1371... | Line 1446... | ||
1371 | //strcpy (image_bootfile, bootfile_pathname); // FIXME: HACK |
1446 | //strcpy (image_bootfile, bootfile_pathname); // FIXME: HACK |
1372 | if (stat (bootfile_pathname, &stat_buf) != 0) |
1447 | if (stat (bootfile_pathname, &stat_buf) != 0) |
1373 | DIE_WITH_EXITCODE (1, "unable to stat the boot file \"%s\" specified in \"%s\" line %d: %s", bootfile_pathname, buildfile_pathname, lineno, strerror (errno)); |
1448 | DIE_WITH_EXITCODE (1, "unable to stat the boot file \"%s\" specified in \"%s\" line %d: %s", bootfile_pathname, buildfile_pathname, lineno, strerror (errno)); |
1374 | bootfile_size = stat_buf.st_size; // save preboot file size |
1449 | bootfile_size = stat_buf.st_size; // save preboot file size |
1375 | LOG_INFO ("processor \"%s\" bootfile \"%s\"\n", image_processor, bootfile_pathname); |
1450 | LOG_INFO ("processor \"%s\" bootfile \"%s\"\n", image_processor, bootfile_pathname); |
1376 | #if 1 |
- | |
1377 | // ###################################################################################################################################################################################################################################### |
- | |
1378 | // # FIXME: figure out how to re-create it: linker call involved |
- | |
1379 | // # $ x86_64-pc-nto-qnx8.0.0-ld --sysroot=${QNX_TARGET}/x86_64/ -T${QNX_TARGET}/x86_64/lib/nto.link --section-start .text=0xffff800000001000 --no-relax ${QNX_TARGET}/x86_64/boot/sys/procnto-smp-instr -o procnto-smp-instr.sym.UNSTRIPPED |
- | |
1380 | // ###################################################################################################################################################################################################################################### |
- | |
1381 | // if (!Buffer_ReadFromFile (&entry_parms.data, kernelfile_pathname)) |
- | |
1382 | // DIE_WITH_EXITCODE (1, "unable to read precompiled kernel file \"%s\" specified in --kernelfile argument: %s", kernelfile_pathname, strerror (errno)); |
- | |
1383 | #else // nonworking |
- | |
1384 |
|
1451 | entry_parms.is_bootstrap_file = true; |
1385 | #endif // nonworking |
- | |
1386 | } |
1452 | } |
1387 | else if (strncmp (token, "mtime=", 6) == 0) { REACH_TOKEN_VALUE (); if (strcmp (value, "*") == 0) entry_parms.mtime = UINT32_MAX; else { |
1453 | else if (strncmp (token, "mtime=", 6) == 0) { REACH_TOKEN_VALUE (); if (strcmp (value, "*") == 0) entry_parms.mtime = UINT32_MAX; else { |
1388 | // value *must* be "YYYY-MM-DD-HH:MM:SS" by specification |
1454 | // value *must* be "YYYY-MM-DD-HH:MM:SS" by specification |
1389 | memset (&utc_time, 0, sizeof (utc_time)); |
1455 | memset (&utc_time, 0, sizeof (utc_time)); |
1390 | if (sscanf_s (value, "%u-%u-%u-%u:%u:%u", &utc_time.tm_year, &utc_time.tm_mon, &utc_time.tm_mday, &utc_time.tm_hour, &utc_time.tm_min, &utc_time.tm_sec) != 6) |
1456 | if (sscanf_s (value, "%u-%u-%u-%u:%u:%u", &utc_time.tm_year, &utc_time.tm_mon, &utc_time.tm_mday, &utc_time.tm_hour, &utc_time.tm_min, &utc_time.tm_sec) != 6) |
Line 1692... | Line 1758... | ||
1692 | DIE_WITH_EXITCODE (1, "the --startupfile arguments expects <pathname>@<entrypoint_from_image_base>"); |
1758 | DIE_WITH_EXITCODE (1, "the --startupfile arguments expects <pathname>@<entrypoint_from_image_base>"); |
1693 | *sep = 0; |
1759 | *sep = 0; |
1694 | startupfile_pathname = argv[arg_index]; |
1760 | startupfile_pathname = argv[arg_index]; |
1695 | startupfile_ep_from_imagebase = (size_t) read_integer (sep + 1); |
1761 | startupfile_ep_from_imagebase = (size_t) read_integer (sep + 1); |
1696 | } |
1762 | } |
1697 | else if ((strcmp (argv[arg_index], "-- |
1763 | else if ((strcmp (argv[arg_index], "--kerneloffs") == 0) && (arg_index + 1 < argc)) // --kerneloffs 0x32000 (undocumented) |
1698 | { |
- | |
1699 | sep = strchr (argv[++arg_index], '@'); |
- | |
1700 | if ((sep == NULL) || (sep[1] == 0)) |
- | |
1701 | DIE_WITH_EXITCODE (1, "the --kernelfile arguments expects <pathname>@<fileoffset>"); |
- | |
1702 | *sep = 0; |
- | |
1703 | kernelfile_pathname = argv[arg_index]; |
- | |
1704 | kernelfile_offset = (size_t) read_integer ( |
1764 | kernelfile_offset = (size_t) read_integer (argv[++arg_index]); |
1705 | } |
- | |
1706 | else if ((strcmp (argv[arg_index], "-a") == 0) && (arg_index + 1 < argc)) // -a suffix |
1765 | else if ((strcmp (argv[arg_index], "-a") == 0) && (arg_index + 1 < argc)) // -a suffix |
1707 | sym_suffix = argv[++arg_index]; |
1766 | sym_suffix = argv[++arg_index]; |
1708 | else if (strcmp (argv[arg_index], "-n") == 0) |
1767 | else if (strcmp (argv[arg_index], "-n") == 0) |
1709 | default_parms.mtime_for_inline_files = 0; // inline files should have a mtime set to zero |
1768 | default_parms.mtime_for_inline_files = 0; // inline files should have a mtime set to zero |
1710 | else if (strcmp (argv[arg_index], "-nn") == 0) |
1769 | else if (strcmp (argv[arg_index], "-nn") == 0) |
Line 1747... | Line 1806... | ||
1747 | saved_ELF_sections = reallocated_ptr; |
1806 | saved_ELF_sections = reallocated_ptr; |
1748 | saved_ELF_sections[saved_ELF_section_count++] = argv[++arg_index]; // stack up another ELF section name to preserve |
1807 | saved_ELF_sections[saved_ELF_section_count++] = argv[++arg_index]; // stack up another ELF section name to preserve |
1749 | } |
1808 | } |
1750 | else if ((strcmp (argv[arg_index], "-?") == 0) || (strcmp (argv[arg_index], "--help") == 0)) |
1809 | else if ((strcmp (argv[arg_index], "-?") == 0) || (strcmp (argv[arg_index], "--help") == 0)) |
1751 | want_help = true; |
1810 | want_help = true; |
1752 | else if (first_pathname == NULL) |
1811 | else if ((first_pathname == NULL) && (*argv[arg_index] != '-')) |
1753 | first_pathname = argv[arg_index]; |
1812 | first_pathname = argv[arg_index]; |
1754 | else if (second_pathname == NULL) |
1813 | else if ((second_pathname == NULL) && (*argv[arg_index] != '-')) |
1755 | second_pathname = argv[arg_index]; |
1814 | second_pathname = argv[arg_index]; |
1756 | else if (third_pathname == NULL) |
1815 | else if ((third_pathname == NULL) && (*argv[arg_index] != '-')) |
1757 | third_pathname = argv[arg_index]; |
1816 | third_pathname = argv[arg_index]; |
1758 | else |
1817 | else |
1759 | DIE_WITH_EXITCODE (1, "unrecognized option: '%s'", argv[arg_index]); |
1818 | DIE_WITH_EXITCODE (1, "unrecognized option: '%s'", argv[arg_index]); |
1760 | } |
1819 | } |
1761 | 1820 | ||
Line 1860... | Line 1919... | ||
1860 | // else do we want to strip an ELF file ? if so, do so |
1919 | // else do we want to strip an ELF file ? if so, do so |
1861 | else if (want_strip) |
1920 | else if (want_strip) |
1862 | { |
1921 | { |
1863 | buffer_t file; |
1922 | buffer_t file; |
1864 | ASSERT (Buffer_ReadFromFile (&file, first_pathname), "can't open \"%s\" for reading: %s", first_pathname, strerror (errno)); |
1923 | ASSERT (Buffer_ReadFromFile (&file, first_pathname), "can't open \"%s\" for reading: %s", first_pathname, strerror (errno)); |
1865 | ASSERT (Buffer_StripELFFile (&file, (const char **) saved_ELF_sections, saved_ELF_section_count, first_pathname), "error stripping \"%s\": %s", first_pathname, strerror (errno)); |
1924 | ASSERT (Buffer_StripELFFile (&file, (const char **) saved_ELF_sections, saved_ELF_section_count, false, first_pathname), "error stripping \"%s\": %s", first_pathname, strerror (errno)); |
1866 | ASSERT_WITH_ERRNO (Buffer_WriteToFile (&file, (second_pathname != NULL ? second_pathname : "<stdout>"))); |
1925 | ASSERT_WITH_ERRNO (Buffer_WriteToFile (&file, (second_pathname != NULL ? second_pathname : "<stdout>"))); |
1867 | exit (0); |
1926 | exit (0); |
1868 | } |
1927 | } |
1869 | 1928 | ||
1870 | // we want to CREATE an IFS file |
1929 | // we want to CREATE an IFS file |
Line 2006... | Line 2065... | ||
2006 | curr_offset += fsentries[fsentry_index].header.size; // advance to the next one |
2065 | curr_offset += fsentries[fsentry_index].header.size; // advance to the next one |
2007 | } |
2066 | } |
2008 | ASSERT_WITH_ERRNO (Buffer_AppendByteArray (&ifs.data, "\0\0\0\0")); // there seems to be 4 bytes of padding after the image directory |
2067 | ASSERT_WITH_ERRNO (Buffer_AppendByteArray (&ifs.data, "\0\0\0\0")); // there seems to be 4 bytes of padding after the image directory |
2009 | imgdir_size = ifs.data.size - ifs.offsets.imagedir; // measure image dir size and save it for future use |
2068 | imgdir_size = ifs.data.size - ifs.offsets.imagedir; // measure image dir size and save it for future use |
2010 | 2069 | ||
2011 | // is it a bootable image with a |
2070 | // is it a bootable image with a startup file ? |
2012 | if |
2071 | if (startupfile_pathname != NULL) |
2013 | { |
2072 | { |
2014 | // start by writing the startup script data blob, if we have one |
2073 | // start by writing the startup script data blob, if we have one |
2015 | for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++) |
2074 | for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++) |
2016 | if (fsentries[fsentry_index].header.ino == image_bootscript_ino) |
2075 | if (fsentries[fsentry_index].header.ino == image_bootscript_ino) |
2017 | break; // locate the startup script directory entry |
2076 | break; // locate the startup script directory entry |
2018 | if (fsentry_index < fsentry_count) // found it ? |
2077 | if (fsentry_index < fsentry_count) // found it ? |
2019 | { |
2078 | { |
2020 | if (ifs.data.size + fsentries[fsentry_index].u.file.size >= kernelfile_offset) |
2079 | if (ifs.data.size + fsentries[fsentry_index].u.file.size >= kernelfile_offset) |
2021 | DIE_WITH_EXITCODE (1, "the compiled startup script is too big (%zd bytes, max is %zd) to fit at current offset %zd", (size_t) fsentries[fsentry_index].u.file.size, kernelfile_offset - ifs.data.size, ifs.data.size); |
2080 | DIE_WITH_EXITCODE (1, "the compiled startup script is too big (%zd bytes, max is %zd) to fit at current offset %zd. Use --kerneloffs <addr> to relocate (warning: untested)", (size_t) fsentries[fsentry_index].u.file.size, kernelfile_offset - ifs.data.size, ifs.data.size); |
2022 | fsentries[fsentry_index].u.file.offset = (uint32_t) (ifs.data.size - ifs.offsets.imageheader); // save file data blob offset in file structure |
2081 | fsentries[fsentry_index].u.file.offset = (uint32_t) (ifs.data.size - ifs.offsets.imageheader); // save file data blob offset in file structure |
2023 | Buffer_AppendIFSFileData (&ifs.data, &fsentries[fsentry_index]); // write file data |
2082 | Buffer_AppendIFSFileData (&ifs.data, &fsentries[fsentry_index]); // write file data |
2024 | fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written |
2083 | fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written |
2025 | } |
2084 | } |
2026 | 2085 | ||
Line 2057... | Line 2116... | ||
2057 | // now write the QNX kernel |
2116 | // now write the QNX kernel |
2058 | for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++) |
2117 | for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++) |
2059 | if (fsentries[fsentry_index].header.ino == image_kernel_ino) |
2118 | if (fsentries[fsentry_index].header.ino == image_kernel_ino) |
2060 | break; // locate the kernel directory entry (can't fail) |
2119 | break; // locate the kernel directory entry (can't fail) |
2061 | fsentries[fsentry_index].u.file.offset = (uint32_t) (ifs.data.size - ifs.offsets.imageheader); // save file data blob offset in file structure |
2120 | fsentries[fsentry_index].u.file.offset = (uint32_t) (ifs.data.size - ifs.offsets.imageheader); // save file data blob offset in file structure |
2062 | #ifdef PROCNTO_WIP |
- | |
2063 | // is the kernel we're storing a preprocessed ELF kernel ? |
- | |
2064 | if (fsentries[fsentry_index].header.ino & IFS_INO_PROCESSED_ELF) |
- | |
2065 | { |
- | |
2066 | elf = (elf_header_t *) fsentries[fsentry_index].u.file.UNSAVED_databuf; // quick access to ELF header |
- | |
2067 | table_count = ELF_GET_NUMERIC (elf, elf, program_header_table_len); // get the number of program headers |
- | |
2068 | for (table_index = 0; table_index < table_count; table_index++) |
- | |
2069 | { |
- | |
2070 | phdr = (elf_program_header_t *) &fsentries[fsentry_index].u.file.UNSAVED_databuf[ELF_GET_NUMERIC (elf, elf, program_header_table_offset) + (size_t) ELF_GET_NUMERIC (elf, elf, program_header_item_size) * table_index]; // quick access to program header |
- | |
2071 | corrective_offset = ELF_GET_NUMERIC (elf, phdr, virtual_addr) - ELF_GET_NUMERIC (elf, phdr, file_offset); |
- | |
2072 | if (ELF_GET_NUMERIC (elf, phdr, size_in_memory) != 0) // only patch the physical address of segments that have an actual size in memory |
- | |
2073 | ELF_SET_NUMERIC (elf, phdr, physical_addr, ELF_GET_NUMERIC (elf, phdr, physical_addr) + image_base + ifs.data.size - corrective_offset); // patch the physical address member of the program header table (NOTE: ifs.data.size is the location where the file data is about to be written) |
- | |
2074 | } |
- | |
2075 | } |
- | |
2076 | #endif // PROCNTO_WIP |
- | |
2077 | Buffer_AppendIFSFileData (&ifs.data, &fsentries[fsentry_index]); // write kernel file data |
2121 | Buffer_AppendIFSFileData (&ifs.data, &fsentries[fsentry_index]); // write kernel file data |
2078 | fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written |
2122 | fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written |
2079 | } |
2123 | } |
2080 | 2124 | ||
2081 | // then write all the other files by increasing inode number: ELF files first |
2125 | // then write all the other files by increasing inode number: ELF files first |