From eb5b018d71875bd837e2a82e8fdf45bb7a6fc207 Mon Sep 17 00:00:00 2001 From: Stafford Horne Date: Fri, 21 Jul 2023 21:55:43 +0100 Subject: [PATCH 1/4] elfload: Fix issue with loading non PROGBITS during section loading During elf section loading the loader loads non program sections by anding with SHT_PROGBITS(0x1). Change the and to an equals to make it correct. We need to change this to actual load using program headers, but I will do that in the next few patches. --- cpu/common/parse.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cpu/common/parse.c b/cpu/common/parse.c index 4db248a..0dc63d0 100644 --- a/cpu/common/parse.c +++ b/cpu/common/parse.c @@ -670,12 +670,11 @@ readfile_elf (char *filename) } } - for (i = 0, elf_spnt = elf_shdata; i < ELF_SHORT_H (elfhdr.e_shnum); i++, elf_spnt++) { - if ((ELF_LONG_H (elf_spnt->sh_type) & SHT_PROGBITS) + if ((ELF_LONG_H (elf_spnt->sh_type) == SHT_PROGBITS) && (ELF_LONG_H (elf_spnt->sh_flags) & SHF_ALLOC)) { From 6914f22ce53db0ce7266dde0e5b43c5f10ffad5f Mon Sep 17 00:00:00 2001 From: Stafford Horne Date: Fri, 21 Jul 2023 22:02:38 +0100 Subject: [PATCH 2/4] elfload: Remove unused breakpoint parameter --- cpu/common/parse.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/cpu/common/parse.c b/cpu/common/parse.c index 0dc63d0..7d28e9e 100644 --- a/cpu/common/parse.c +++ b/cpu/common/parse.c @@ -102,13 +102,11 @@ strstrip (char *dst, physical address is equal to logical. @param[in] laddr Logical address - @param[in] breakpoint Unused @return The physical address */ /*---------------------------------------------------------------------------*/ static oraddr_t -translate (oraddr_t laddr, - int *breakpoint) +translate (oraddr_t laddr) { int i; @@ -276,17 +274,14 @@ check_insn (uint32_t insn) @note insn must be in big endian format @param[in] address The address to use - @param[in] insn The instruction to add - @param[in] breakpoint Not used (it is passed to the translate() function, - which also does not use it. */ + @param[in] insn The instruction to add */ /*---------------------------------------------------------------------------*/ static void addprogram (oraddr_t address, - uint32_t insn, - int *breakpoint) + uint32_t insn) { - int vaddr = (!runtime.sim.filename) ? translate (address, breakpoint) : - translate (freemem, breakpoint); + int vaddr = (!runtime.sim.filename) ? translate (address) : + translate (freemem); /* We can't have set_program32 functions since it is not gauranteed that the section we're loading is aligned on a 4-byte boundry */ @@ -324,7 +319,6 @@ readfile_coff (char *filename, struct COFF_scnhdr coffscnhdr; int len; int firstthree = 0; - int breakpoint = 0; if (!(inputfs = fopen (filename, "r"))) { @@ -390,7 +384,7 @@ readfile_coff (char *filename, fseek (inputfs, -2, SEEK_CUR); } - addprogram (freemem, insn, &breakpoint); + addprogram (freemem, insn); sectsize -= len; } } @@ -508,7 +502,6 @@ readfile_elf (char *filename) uint32_t syms = 0; char *str_tbl = (char *) 0; char *s_str = (char *) 0; - int breakpoint = 0; uint32_t inputbuf; uint32_t padd; uint32_t insn; @@ -724,7 +717,7 @@ readfile_elf (char *filename) && (len = fread (&inputbuf, sizeof (inputbuf), 1, inputfs))) { insn = ELF_LONG_H (inputbuf); - addprogram (freemem, insn, &breakpoint); + addprogram (freemem, insn); sectsize -= 4; } } @@ -859,8 +852,6 @@ identifyfile (char *filename) uint32_t loadcode (char *filename, oraddr_t startaddr, oraddr_t virtphy_transl) { - int breakpoint = 0; - transl_error = 0; transl_table = virtphy_transl; freemem = startaddr; @@ -886,6 +877,6 @@ loadcode (char *filename, oraddr_t startaddr, oraddr_t virtphy_transl) if (transl_error) return -1; else - return translate (freemem, &breakpoint); + return translate (freemem); } From cffcafd5efd69d2bf648db2515312bfcca72d101 Mon Sep 17 00:00:00 2001 From: Stafford Horne Date: Sat, 22 Jul 2023 22:22:16 +0100 Subject: [PATCH 3/4] elfload: Fixup indentation, style and add some comments --- cpu/common/parse.c | 91 +++++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 45 deletions(-) diff --git a/cpu/common/parse.c b/cpu/common/parse.c index 7d28e9e..c93e59b 100644 --- a/cpu/common/parse.c +++ b/cpu/common/parse.c @@ -498,10 +498,10 @@ readfile_elf (char *filename) struct elf32_hdr elfhdr; struct elf32_phdr *elf_phdata = NULL; struct elf32_shdr *elf_spstr, *elf_spnt, *elf_shdata; - struct elf32_sym *sym_tbl = (struct elf32_sym *) 0; + struct elf32_sym *sym_tbl = NULL; uint32_t syms = 0; - char *str_tbl = (char *) 0; - char *s_str = (char *) 0; + char *str_tbl = NULL; + char *s_str = NULL; uint32_t inputbuf; uint32_t padd; uint32_t insn; @@ -513,12 +513,14 @@ readfile_elf (char *filename) exit (1); } + /* Load elf header */ if (fread (&elfhdr, sizeof (elfhdr), 1, inputfs) != 1) { perror ("readfile_elf"); exit (1); } + /* Read in elf section header */ if ((elf_shdata = (struct elf32_shdr *) malloc (ELF_SHORT_H (elfhdr.e_shentsize) * ELF_SHORT_H (elfhdr.e_shnum))) == NULL) @@ -542,6 +544,7 @@ readfile_elf (char *filename) exit (1); } + /* Read in elf program headers if available */ if (ELF_LONG_H (elfhdr.e_phoff)) { if ((elf_phdata = @@ -569,18 +572,15 @@ readfile_elf (char *filename) } } + /* Look for symbol table section and load string table. Used + for inserting symbol labels. */ for (i = 0, elf_spnt = elf_shdata; i < ELF_SHORT_H (elfhdr.e_shnum); i++, elf_spnt++) { - - if (ELF_LONG_H (elf_spnt->sh_type) == SHT_SYMTAB) { - if (NULL != sym_tbl) - { - free (sym_tbl); - } + free (sym_tbl); if ((sym_tbl = (struct elf32_sym *) malloc (ELF_LONG_H (elf_spnt->sh_size))) @@ -608,38 +608,37 @@ readfile_elf (char *filename) ELF_LONG_H (elf_spnt->sh_size) / ELF_LONG_H (elf_spnt->sh_entsize); - if (ELF_LONG_H (elf_spnt->sh_link) <= ELF_SHORT_H (elfhdr.e_shnum)) - { - if (NULL != str_tbl) - { - free (str_tbl); - } + if (ELF_LONG_H (elf_spnt->sh_link) <= ELF_SHORT_H (elfhdr.e_shnum)) + { + if (NULL != str_tbl) + free (str_tbl); - elf_spstr = &elf_shdata[ELF_LONG_H (elf_spnt->sh_link)]; - if ((str_tbl = - (char *) malloc (ELF_LONG_H (elf_spstr->sh_size))) == NULL) - { - perror ("readfile_elf"); - exit (1); - } + elf_spstr = &elf_shdata[ELF_LONG_H (elf_spnt->sh_link)]; + if ((str_tbl = + (char *) malloc (ELF_LONG_H (elf_spstr->sh_size))) == NULL) + { + perror ("readfile_elf"); + exit (1); + } - if (fseek (inputfs, ELF_LONG_H (elf_spstr->sh_offset), SEEK_SET) != - 0) - { - perror ("readfile_elf"); - exit (1); - } + if (fseek (inputfs, ELF_LONG_H (elf_spstr->sh_offset), SEEK_SET) != + 0) + { + perror ("readfile_elf"); + exit (1); + } - if (fread (str_tbl, ELF_LONG_H (elf_spstr->sh_size), 1, inputfs) != - 1) - { - perror ("readfile_elf"); - exit (1); - } + if (fread (str_tbl, ELF_LONG_H (elf_spstr->sh_size), 1, inputfs) != + 1) + { + perror ("readfile_elf"); + exit (1); } + } } } + /* Load section name string table. Used for printing section names. */ if (ELF_SHORT_H (elfhdr.e_shstrndx) != SHN_UNDEF) { elf_spnt = &elf_shdata[ELF_SHORT_H (elfhdr.e_shstrndx)]; @@ -663,6 +662,7 @@ readfile_elf (char *filename) } } + /* Iterate over section headers and load program bits. */ for (i = 0, elf_spnt = elf_shdata; i < ELF_SHORT_H (elfhdr.e_shnum); i++, elf_spnt++) { @@ -672,6 +672,9 @@ readfile_elf (char *filename) { padd = ELF_LONG_H (elf_spnt->sh_addr); + /* Search if section is within program header segment, if + so adjust the paddr to use the physical address of the + segment. */ for (j = 0; j < ELF_SHORT_H (elfhdr.e_phnum); j++) { if (ELF_LONG_H (elf_phdata[j].p_offset) && @@ -686,8 +689,6 @@ readfile_elf (char *filename) ELF_LONG_H (elf_phdata[j].p_offset); } - - if (ELF_LONG_H (elf_spnt->sh_name) && s_str) { PRINTFQ ("Section: %s,", &s_str[ELF_LONG_H (elf_spnt->sh_name)]); @@ -723,6 +724,7 @@ readfile_elf (char *filename) } } + /* Load up sym_tbl symbols and names from str_tbl into symbol to label hash. */ if (str_tbl) { i = 0; @@ -739,19 +741,18 @@ readfile_elf (char *filename) } if (NULL != str_tbl) - { - free (str_tbl); - } + free (str_tbl); if (NULL != sym_tbl) - { - free (sym_tbl); - } + free (sym_tbl); - free (s_str); - free (elf_phdata); - free (elf_shdata); + if (NULL != s_str) + free (s_str); + + if (NULL != elf_phdata) + free (elf_phdata); + free (elf_shdata); } /* Identify file type and call appropriate readfile_X routine. It only From 5365380901b64897f0eb65b323ee71cd7f3c9ee0 Mon Sep 17 00:00:00 2001 From: Stafford Horne Date: Sat, 22 Jul 2023 23:38:50 +0100 Subject: [PATCH 4/4] elfload: Load files by program headers by default This adds a new function to load program segments by program header, we then fall back to section headers if that does not work. The loading of section headers and labels is split out to functions to make if/else logic readable. --- cpu/common/parse.c | 364 +++++++++++++++++++++++++++------------------ 1 file changed, 223 insertions(+), 141 deletions(-) diff --git a/cpu/common/parse.c b/cpu/common/parse.c index c93e59b..8b603f3 100644 --- a/cpu/common/parse.c +++ b/cpu/common/parse.c @@ -490,192 +490,108 @@ readsyms_coff (char *filename, uint32_t symptr, uint32_t syms) return; } -static void -readfile_elf (char *filename) +static int +load_by_program_headers_elf (FILE *inputfs, + struct elf32_hdr *elfhdr, + struct elf32_phdr *elf_phdata) { + int segments_loaded = 0; + int i, len; - FILE *inputfs; - struct elf32_hdr elfhdr; - struct elf32_phdr *elf_phdata = NULL; - struct elf32_shdr *elf_spstr, *elf_spnt, *elf_shdata; - struct elf32_sym *sym_tbl = NULL; - uint32_t syms = 0; - char *str_tbl = NULL; - char *s_str = NULL; - uint32_t inputbuf; - uint32_t padd; - uint32_t insn; - int i, j, sectsize, len; - - if (!(inputfs = fopen (filename, "r"))) - { - perror ("readfile_elf"); - exit (1); - } - - /* Load elf header */ - if (fread (&elfhdr, sizeof (elfhdr), 1, inputfs) != 1) - { - perror ("readfile_elf"); - exit (1); - } - - /* Read in elf section header */ - if ((elf_shdata = - (struct elf32_shdr *) malloc (ELF_SHORT_H (elfhdr.e_shentsize) * - ELF_SHORT_H (elfhdr.e_shnum))) == NULL) + /* Iterate over prgram headers and load PT_LOAD segments. */ + for (i = 0; i < ELF_SHORT_H (elfhdr->e_phnum); i++) { - perror ("readfile_elf"); - exit (1); - } + struct elf32_phdr *ph = &elf_phdata[i]; - if (fseek (inputfs, ELF_LONG_H (elfhdr.e_shoff), SEEK_SET) != 0) - { - perror ("readfile_elf"); - exit (1); - } - - if (fread - (elf_shdata, - ELF_SHORT_H (elfhdr.e_shentsize) * ELF_SHORT_H (elfhdr.e_shnum), 1, - inputfs) != 1) - { - perror ("readfile_elf"); - exit (1); - } - - /* Read in elf program headers if available */ - if (ELF_LONG_H (elfhdr.e_phoff)) - { - if ((elf_phdata = - (struct elf32_phdr *) malloc (ELF_SHORT_H (elfhdr.e_phnum) * - ELF_SHORT_H (elfhdr.e_phentsize))) == - NULL) + if (ELF_LONG_H (ph->p_type) == PT_LOAD) { - perror ("readfile_elf"); - exit (1); - } - - if (fseek (inputfs, ELF_LONG_H (elfhdr.e_phoff), SEEK_SET) != 0) - { - perror ("readfile_elf"); - exit (1); - } + uint32_t padd = ELF_LONG_H (ph->p_paddr); + uint32_t inputbuf, insn; + int segsize; - if (fread - (elf_phdata, - ELF_SHORT_H (elfhdr.e_phnum) * ELF_SHORT_H (elfhdr.e_phentsize), - 1, inputfs) != 1) - { - perror ("readfile_elf"); - exit (1); - } - } - - /* Look for symbol table section and load string table. Used - for inserting symbol labels. */ - for (i = 0, elf_spnt = elf_shdata; i < ELF_SHORT_H (elfhdr.e_shnum); - i++, elf_spnt++) - { - if (ELF_LONG_H (elf_spnt->sh_type) == SHT_SYMTAB) - { - if (NULL != sym_tbl) - free (sym_tbl); + PRINTFQ ("Program Header: PT_LOAD,"); + PRINTFQ (" vaddr: 0x%.8lx,", ELF_LONG_H (ph->p_vaddr)); + PRINTFQ (" paddr: 0x%" PRIx32, padd); + PRINTFQ (" offset: 0x%.8lx,", ELF_LONG_H (ph->p_offset)); + PRINTFQ (" filesz: 0x%.8lx,", ELF_LONG_H (ph->p_filesz)); + PRINTFQ (" memsz: 0x%.8lx\n", ELF_LONG_H (ph->p_memsz)); - if ((sym_tbl = - (struct elf32_sym *) malloc (ELF_LONG_H (elf_spnt->sh_size))) - == NULL) - { - perror ("readfile_elf"); - exit (1); - } + freemem = padd; + segsize = ELF_LONG_H (ph->p_filesz); - if (fseek (inputfs, ELF_LONG_H (elf_spnt->sh_offset), SEEK_SET) != + if (fseek (inputfs, ELF_LONG_H (ph->p_offset), SEEK_SET) != 0) { - perror ("readfile_elf"); - exit (1); + perror ("laod_by_program_headers_elf"); + return -1; } - if (fread (sym_tbl, ELF_LONG_H (elf_spnt->sh_size), 1, inputfs) != - 1) + while (segsize > 0 + && (len = fread (&inputbuf, sizeof (inputbuf), 1, inputfs))) { - perror ("readfile_elf"); - exit (1); + insn = ELF_LONG_H (inputbuf); + addprogram (freemem, insn); + segsize -= 4; } - syms = - ELF_LONG_H (elf_spnt->sh_size) / - ELF_LONG_H (elf_spnt->sh_entsize); - - if (ELF_LONG_H (elf_spnt->sh_link) <= ELF_SHORT_H (elfhdr.e_shnum)) - { - if (NULL != str_tbl) - free (str_tbl); - - elf_spstr = &elf_shdata[ELF_LONG_H (elf_spnt->sh_link)]; - if ((str_tbl = - (char *) malloc (ELF_LONG_H (elf_spstr->sh_size))) == NULL) - { - perror ("readfile_elf"); - exit (1); - } - - if (fseek (inputfs, ELF_LONG_H (elf_spstr->sh_offset), SEEK_SET) != - 0) - { - perror ("readfile_elf"); - exit (1); - } - - if (fread (str_tbl, ELF_LONG_H (elf_spstr->sh_size), 1, inputfs) != - 1) - { - perror ("readfile_elf"); - exit (1); - } - } + segments_loaded++; } } + return segments_loaded; +} + +static int +load_by_section_headers_elf (FILE *inputfs, + struct elf32_hdr *elfhdr, + struct elf32_phdr *elf_phdata, + struct elf32_shdr *elf_shdata) +{ + char *s_str = NULL; + struct elf32_shdr *elf_spnt; + int sections_loaded = 0; + int i, j, len; /* Load section name string table. Used for printing section names. */ - if (ELF_SHORT_H (elfhdr.e_shstrndx) != SHN_UNDEF) + if (ELF_SHORT_H (elfhdr->e_shstrndx) != SHN_UNDEF) { - elf_spnt = &elf_shdata[ELF_SHORT_H (elfhdr.e_shstrndx)]; + elf_spnt = &elf_shdata[ELF_SHORT_H (elfhdr->e_shstrndx)]; if ((s_str = (char *) malloc (ELF_LONG_H (elf_spnt->sh_size))) == NULL) { - perror ("readfile_elf"); + perror ("load_by_section_headers_elf"); exit (1); } if (fseek (inputfs, ELF_LONG_H (elf_spnt->sh_offset), SEEK_SET) != 0) { - perror ("readfile_elf"); + perror ("load_by_section_headers_elf"); exit (1); } if (fread (s_str, ELF_LONG_H (elf_spnt->sh_size), 1, inputfs) != 1) { - perror ("readfile_elf"); + perror ("load_by_section_headers_elf"); exit (1); } } /* Iterate over section headers and load program bits. */ - for (i = 0, elf_spnt = elf_shdata; i < ELF_SHORT_H (elfhdr.e_shnum); + for (i = 0, elf_spnt = elf_shdata; i < ELF_SHORT_H (elfhdr->e_shnum); i++, elf_spnt++) { if ((ELF_LONG_H (elf_spnt->sh_type) == SHT_PROGBITS) && (ELF_LONG_H (elf_spnt->sh_flags) & SHF_ALLOC)) { + uint32_t padd; + uint32_t inputbuf, insn; + int sectsize; padd = ELF_LONG_H (elf_spnt->sh_addr); /* Search if section is within program header segment, if so adjust the paddr to use the physical address of the segment. */ - for (j = 0; j < ELF_SHORT_H (elfhdr.e_phnum); j++) + for (j = 0; j < ELF_SHORT_H (elfhdr->e_phnum); j++) { if (ELF_LONG_H (elf_phdata[j].p_offset) && ELF_LONG_H (elf_phdata[j].p_offset) <= @@ -709,8 +625,7 @@ readfile_elf (char *filename) if (fseek (inputfs, ELF_LONG_H (elf_spnt->sh_offset), SEEK_SET) != 0) { - perror ("readfile_elf"); - free (elf_phdata); + perror ("load_by_section_headers_elf"); exit (1); } @@ -721,6 +636,91 @@ readfile_elf (char *filename) addprogram (freemem, insn); sectsize -= 4; } + + sections_loaded++; + } + } + + if (NULL != s_str) + free (s_str); + + return sections_loaded; +} + +static void +load_labels_elf (FILE *inputfs, + struct elf32_hdr *elfhdr, + struct elf32_shdr *elf_shdata) +{ + struct elf32_shdr *elf_spstr, *elf_spnt; + struct elf32_sym *sym_tbl = NULL; + uint32_t syms = 0; + char *str_tbl = NULL; + int i; + + /* Look for symbol table section and load string table. Used + for inserting symbol labels. */ + for (i = 0, elf_spnt = elf_shdata; i < ELF_SHORT_H (elfhdr->e_shnum); + i++, elf_spnt++) + { + if (ELF_LONG_H (elf_spnt->sh_type) == SHT_SYMTAB) + { + if (NULL != sym_tbl) + free (sym_tbl); + + if ((sym_tbl = + (struct elf32_sym *) malloc (ELF_LONG_H (elf_spnt->sh_size))) + == NULL) + { + perror ("load_labels_elf"); + exit (1); + } + + if (fseek (inputfs, ELF_LONG_H (elf_spnt->sh_offset), SEEK_SET) != + 0) + { + perror ("load_labels_elf"); + exit (1); + } + + if (fread (sym_tbl, ELF_LONG_H (elf_spnt->sh_size), 1, inputfs) != + 1) + { + perror ("load_labels_elf"); + exit (1); + } + + syms = + ELF_LONG_H (elf_spnt->sh_size) / + ELF_LONG_H (elf_spnt->sh_entsize); + + if (ELF_LONG_H (elf_spnt->sh_link) <= ELF_SHORT_H (elfhdr->e_shnum)) + { + if (NULL != str_tbl) + free (str_tbl); + + elf_spstr = &elf_shdata[ELF_LONG_H (elf_spnt->sh_link)]; + if ((str_tbl = + (char *) malloc (ELF_LONG_H (elf_spstr->sh_size))) == NULL) + { + perror ("load_labels_elf"); + exit (1); + } + + if (fseek (inputfs, ELF_LONG_H (elf_spstr->sh_offset), SEEK_SET) != + 0) + { + perror ("load_labels_elf"); + exit (1); + } + + if (fread (str_tbl, ELF_LONG_H (elf_spstr->sh_size), 1, inputfs) != + 1) + { + perror ("load_labels_elf"); + exit (1); + } + } } } @@ -745,9 +745,91 @@ readfile_elf (char *filename) if (NULL != sym_tbl) free (sym_tbl); +} - if (NULL != s_str) - free (s_str); +static void +readfile_elf (char *filename) +{ + + FILE *inputfs; + struct elf32_hdr elfhdr; + struct elf32_phdr *elf_phdata = NULL; + struct elf32_shdr *elf_shdata; + int loaded; + + if (!(inputfs = fopen (filename, "r"))) + { + perror ("readfile_elf"); + exit (1); + } + + /* Load elf header */ + if (fread (&elfhdr, sizeof (elfhdr), 1, inputfs) != 1) + { + perror ("readfile_elf"); + exit (1); + } + + /* Read in elf section header */ + if ((elf_shdata = + (struct elf32_shdr *) malloc (ELF_SHORT_H (elfhdr.e_shentsize) * + ELF_SHORT_H (elfhdr.e_shnum))) == NULL) + { + perror ("readfile_elf"); + exit (1); + } + + if (fseek (inputfs, ELF_LONG_H (elfhdr.e_shoff), SEEK_SET) != 0) + { + perror ("readfile_elf"); + exit (1); + } + + if (fread + (elf_shdata, + ELF_SHORT_H (elfhdr.e_shentsize) * ELF_SHORT_H (elfhdr.e_shnum), 1, + inputfs) != 1) + { + perror ("readfile_elf"); + exit (1); + } + + /* Read in elf program headers if available */ + if (ELF_LONG_H (elfhdr.e_phoff)) + { + if ((elf_phdata = + (struct elf32_phdr *) malloc (ELF_SHORT_H (elfhdr.e_phnum) * + ELF_SHORT_H (elfhdr.e_phentsize))) == + NULL) + { + perror ("readfile_elf"); + exit (1); + } + + if (fseek (inputfs, ELF_LONG_H (elfhdr.e_phoff), SEEK_SET) != 0) + { + perror ("readfile_elf"); + exit (1); + } + + if (fread + (elf_phdata, + ELF_SHORT_H (elfhdr.e_phnum) * ELF_SHORT_H (elfhdr.e_phentsize), + 1, inputfs) != 1) + { + perror ("readfile_elf"); + exit (1); + } + } + + loaded = load_by_program_headers_elf(inputfs, &elfhdr, elf_phdata); + if (loaded <= 0) + { + loaded = load_by_section_headers_elf(inputfs, &elfhdr, + elf_phdata, elf_shdata); + } + if (loaded) + load_labels_elf(inputfs, &elfhdr, elf_shdata); if (NULL != elf_phdata) free (elf_phdata);