Commit bbb0d352a35fee2d22bb2eb9ffbfd5bb62280127
receivedFri, 2. Dec 2022, 11:21:39 (by user sx)
Fri, 2 Dec 2022 10:21:39 +0000 (11:21 +0100)
authorManfred Steiner <sx@htl-kaindorf.at>
Fri, 2 Dec 2022 10:21:35 +0000 (11:21 +0100)
committerManfred Steiner <sx@htl-kaindorf.at>
Fri, 2 Dec 2022 10:21:35 +0000 (11:21 +0100)
simavr/sim/sim_elf.c

index 371b9dba19fc77a3aab46ba1807d671eca08ce59..246af5772cecf87b0a936e0eda3f61d6d1856cde 100644 (file)
@@ -279,7 +279,7 @@ elf_copy_segment(int fd, Elf32_Phdr *php, uint8_t **dest)
 
        if (*dest == NULL)
                *dest = malloc(php->p_filesz);
-       if (!*dest)
+       if (*dest == NULL)
                return -1;
 
        lseek(fd, php->p_offset, SEEK_SET);
@@ -291,8 +291,6 @@ elf_copy_segment(int fd, Elf32_Phdr *php, uint8_t **dest)
                                rv, php->p_filesz, php->p_vaddr, php->p_offset);
                return -1;
        }
-       AVR_LOG(NULL, LOG_DEBUG, "Loaded %d bytes at 0x%04x\n",
-                       php->p_filesz, php->p_vaddr);
        return 0;
 }
 
@@ -304,10 +302,15 @@ elf_handle_segment(int fd, Elf32_Phdr *php, uint8_t **dest, const char *name)
                                "Unexpected extra %s data: %d bytes at %x.\n",
                                name, php->p_filesz, php->p_vaddr);
                return -1;
-       } else {
-               elf_copy_segment(fd, php, dest);
-               return 0;
+       } else if (elf_copy_segment(fd, php, dest)) {
+               AVR_LOG(NULL, LOG_ERROR,
+                               "copy segment fails (%d bytes at %x)!\n",
+                               name, php->p_filesz, php->p_vaddr);
+               return -1;
        }
+       AVR_LOG(NULL, LOG_DEBUG, "  Loaded %d (0x%0x) bytes (section offset 0x%04x)\n",
+               php->p_filesz, php->p_filesz, php->p_vaddr);
+       return 0;
 }
 
 /* The structure *firmware must be pre-initialised to zero, then optionally
@@ -363,6 +366,8 @@ elf_read_firmware(
                return -1;
        }
 
+       int isTextSectionLoaded = 0;
+       uint32_t offset = 0;
        for (i = 0; i < (int)ph_count; ++i, ++php) {
 #if 0
                printf("Header %d type %d addr %x/%x size %d/%d flags %x\n",
@@ -371,62 +376,90 @@ elf_read_firmware(
 #endif
                if (php->p_type != PT_LOAD || php->p_filesz == 0)
                        continue;
-               if (php->p_vaddr < 0x800000) {
-                       /* Explicit flash section. Load it. */
+
+               if (php->p_vaddr < 0x810000) {  // .text or .data section
                        if (firmware->flash == NULL) {
+                               avr_t *avr = avr_make_mcu_by_name(firmware->mmcu);
                                firmware->flashbase = 0;
-                               firmware->flashsize = php->p_vaddr + php->p_filesz;
-                               firmware->flash = malloc(firmware->flashsize);
-                               memset(firmware->flash, 0xff, firmware->flashsize);
-                               uint8_t *where = firmware->flash + php->p_vaddr;
-                               elf_copy_segment(fd, php, &where);
-
-                       } else {
-                               long gapSize = php->p_vaddr - firmware->flashsize;
-                               if (gapSize < 0) {
-                                       AVR_LOG(NULL, LOG_ERROR,
-                                               "Overlapping flash sections!\n");
+                               firmware->flashsize = avr->flashend + 1;
+                               if (firmware->flashsize <= 0) {
+                                       AVR_LOG(NULL, LOG_ERROR, "cannot initialize flash, unknown size!\n");
                                        return -1;
-                               } else  if (gapSize > 0) {
-                                       firmware->flash = realloc(firmware->flash,php->p_vaddr );
-                                       uint8_t *where = firmware->flash + firmware->flashsize;
-                                       memset(where, 0xff, gapSize);
-                                       firmware->flashsize = php->p_vaddr;
                                }
-                               firmware->flash = realloc(firmware->flash,
-                                                                                 firmware->flashsize + php->p_filesz);
-                               if (!firmware->flash)
+                               firmware->flash = (uint8_t *)malloc(firmware->flashsize);
+                               if (firmware->flash == NULL) {
+                                       AVR_LOG(NULL, LOG_ERROR, "malloc flash memory fails!\n");
                                        return -1;
-                               uint8_t *where = firmware->flash + firmware->flashsize;
-                               elf_copy_segment(fd, php, &where);
-                               firmware->flashsize += php->p_filesz;
+                               }
+                               memset(firmware->flash, 0xff, firmware->flashsize);
+                               AVR_LOG(NULL, LOG_DEBUG, "flash initialization with 0xff (%d bytes)\n", firmware->flashsize);
                        }
 
-               } else if (php->p_vaddr < 0x810000) {
-                       /* Data space.  If there are initialised variables, treat
-                        * them as extra initialised flash.  The C startup function
-                        * understands that and will copy them to RAM.
-                        */
-
-                       if (firmware->flash != NULL) {
-                               uint8_t *where;
-
-                               firmware->flash = realloc(firmware->flash,
-                                                                                 firmware->flashsize + php->p_filesz);
-                               if (!firmware->flash)
-                                       return -1;
-                               where = firmware->flash + firmware->flashsize;
-                               elf_copy_segment(fd, php, &where);
-                               AVR_LOG(NULL, LOG_DEBUG, ".data section %d bytes copied to flash at 0x%04x\n", php->p_filesz, firmware->flashsize);
-                               firmware->flashsize += php->p_filesz;
-                       } else {
-                               /* If this ever happens, add a second pass. */
-
+                       if (php->p_vaddr < 0x800000) {
+                               /* Explicit flash section. Load it. */
+                               isTextSectionLoaded = 1;
+                               offset = php->p_vaddr;
+                       } else if (isTextSectionLoaded ) {
+                               /* Data space.  If there are initialised variables, treat
+                               * them as extra initialised flash.  The C startup function
+                               * understands that and will copy them to RAM.
+                               */
+                               isTextSectionLoaded = 0;
+                       } else if (!isTextSectionLoaded) {
                                AVR_LOG(NULL, LOG_ERROR,
-                                               "Initialialised data but no flash (%d bytes at %x)!\n",
-                                               php->p_filesz, php->p_vaddr);
+                                               "Initialialised data but no flash (%d bytes at %x in file \"%s\")!\n",
+                                               php->p_filesz, php->p_vaddr, file);
                                return -1;
                        }
+                       uint8_t *section = NULL;
+                       if (elf_copy_segment(fd, php, &section) || section == NULL) {
+                               AVR_LOG(NULL, LOG_ERROR,
+                                       "cannot read section (%d bytes at %x in file \"%s\")!\n",
+                                       php->p_filesz, php->p_vaddr, file);
+                               if (section != NULL) {
+                                       free(section);
+                                       section = NULL;
+                               }
+                               return -1;
+                       } else {
+                               AVR_LOG(NULL, LOG_DEBUG, "  Loading %d (0x%0x) bytes (section offset 0x%04x) to flash address 0x%04x\n",
+                                       php->p_filesz, php->p_filesz, php->p_vaddr, offset);
+                       }
+
+                       uint32_t overlapping_start = UINT32_MAX;
+                       uint32_t overlapping_end = 0;
+                       int overlapping_error = 0;
+                       for (uint32_t addr = offset; addr < (offset + php->p_filesz); addr++) {
+                               if (addr >= firmware->flashsize) {
+                                       AVR_LOG(NULL, LOG_ERROR,
+                                               "section out of flash address range (%d bytes at %x in file \"%s\")!\n",
+                                               php->p_filesz, php->p_vaddr, file);
+                                       return -1;
+                               }
+                               if (firmware->flash[addr] != 0xff) {
+                                       overlapping_start = addr < overlapping_start ? addr : overlapping_start;
+                                       overlapping_end = addr > overlapping_end ? addr : overlapping_end;
+                                       if (firmware->flash[addr] != section[addr - offset]) {
+                                               overlapping_error = 1;
+                                       }
+                               }
+                               firmware->flash[addr] = section[addr - offset];
+                       }
+                       offset += php->p_filesz;
+                       if (overlapping_start <= overlapping_end) {
+                               if (overlapping_error) {
+                                       AVR_LOG(NULL, LOG_OUTPUT,
+                                               "WARNING: overlapping section with different content (0x%04x..0x%04x)!\n",
+                                               overlapping_start, overlapping_end);
+                               } else {
+                                       AVR_LOG(NULL, LOG_OUTPUT,
+                                               "overlapping section with same content (0x%04x..0x%04x)!\n",
+                                               overlapping_start, overlapping_end);
+                               }
+                       }
+                       free(section);
+                       section = NULL;
+
                } else if (php->p_vaddr < 0x820000) {
                        /* EEPROM. */
 
@@ -446,27 +479,6 @@ elf_read_firmware(
                }
        }
 
-       avr_t *avr = avr_make_mcu_by_name(firmware->mmcu);
-       if (avr != NULL) {
-               if (firmware->flash == NULL) {
-                       AVR_LOG(NULL, LOG_ERROR,
-                                       "no flash!\n",
-                                       php->p_filesz, php->p_vaddr);
-                       return -1;
-               } else {
-                       long gapSize = avr->flashend + 1 - firmware->flashsize;
-                       if (gapSize < 0) {
-                               AVR_LOG(NULL, LOG_ERROR,
-                                       "flash size 0x%04x too large for selected mmcu device %s!\n", firmware->flashsize, firmware->mmcu);
-                               return -1;
-                       } else  if (gapSize > 0) {
-                               firmware->flash = realloc(firmware->flash, firmware->flashsize + gapSize);
-                               uint8_t *where = firmware->flash + firmware->flashsize;
-                               memset(where, 0xff, gapSize);
-                               firmware->flashsize += gapSize;
-                       }
-               }
-       }
        /* Scan the section table for .mmcu magic and symbols. */
 
        while ((scn = elf_nextscn(elf, scn)) != NULL) {
@@ -539,9 +551,9 @@ elf_read_firmware(
                }
 #endif // ELF_SYMBOLS
        }
-       if (firmware->flash != NULL) {
-               AVR_LOG(NULL, LOG_DEBUG, "end of flash initialization (size=0x%04x)\n", firmware->flashsize);
-       }
+       // if (firmware->flash != NULL) {
+       //      AVR_LOG(NULL, LOG_DEBUG, "end of flash initialization (size=0x%04x)\n", firmware->flashsize);
+       // }
        elf_end(elf);
        close(fd);
        return 0;