diff --git a/tools/elf2uf2/main.cpp b/tools/elf2uf2/main.cpp index 77e67c7..f8d635e 100644 --- a/tools/elf2uf2/main.cpp +++ b/tools/elf2uf2/main.cpp @@ -129,7 +129,7 @@ int check_address_range(const address_ranges& valid_ranges, uint32_t addr, uint3 for(const auto& range : valid_ranges) { if (range.from <= addr && range.to >= addr + size) { if (range.type == address_range::type::NO_CONTENTS && !uninitialized) { - return fail(ERROR_INCOMPATIBLE, "ELF contains memory contents for uninitialized memory"); + return fail(ERROR_INCOMPATIBLE, "ELF contains memory contents for uninitialized memory at 0x%p", addr); } ar = range; if (verbose) { @@ -142,61 +142,64 @@ int check_address_range(const address_ranges& valid_ranges, uint32_t addr, uint3 return fail(ERROR_INCOMPATIBLE, "Memory segment %08x->%08x is outside of valid address range for device", addr, addr+size); } -int read_and_check_elf32_ph_entries(FILE *in, const elf32_header &eh, const address_ranges& valid_ranges, std::map>& pages) { +int read_elf32_ph_entries(FILE *in, const elf32_header &eh, std::vector& entries) { if (eh.ph_entry_size != sizeof(elf32_ph_entry)) { return fail(ERROR_FORMAT, "Invalid ELF32 program header"); } if (eh.ph_num) { - std::vector entries(eh.ph_num); + entries.resize(eh.ph_num); if (fseek(in, eh.ph_offset, SEEK_SET)) { return fail_read_error(); } if (eh.ph_num != fread(&entries[0], sizeof(struct elf32_ph_entry), eh.ph_num, in)) { return fail_read_error(); } - for(uint i=0;i& entries, const address_ranges& valid_ranges, std::map>& pages) { + for(const auto & entry : entries) { + if (entry.type == PT_LOAD && entry.memsz) { + address_range ar; + int rc; + uint mapped_size = std::min(entry.filez, entry.memsz); + if (mapped_size) { + rc = check_address_range(valid_ranges, entry.paddr, entry.vaddr, mapped_size, false, ar); + if (rc) return rc; + // we don't download uninitialized, generally it is BSS and should be zero-ed by crt0.S, or it may be COPY areas which are undefined + if (ar.type != address_range::type::CONTENTS) { + if (verbose) printf(" ignored\n"); + continue; + } + uint addr = entry.paddr; + uint remaining = mapped_size; + uint file_offset = entry.offset; + while (remaining) { + uint off = addr & (PAGE_SIZE - 1); + uint len = std::min(remaining, PAGE_SIZE - off); + auto &fragments = pages[addr - off]; // list of fragments + // note if filesz is zero, we want zero init which is handled because the + // statement above creates an empty page fragment list + // check overlap with any existing fragments + for (const auto &fragment : fragments) { + if ((off < fragment.page_offset + fragment.bytes) != + ((off + len) <= fragment.page_offset)) { + fail(ERROR_FORMAT, "In memory segments overlap"); } - fragments.push_back( - page_fragment{file_offset,off,len}); - addr += len; - file_offset += len; - remaining -= len; } + fragments.push_back( + page_fragment{file_offset,off,len}); + addr += len; + file_offset += len; + remaining -= len; } - if (entry.memsz > entry.filez) { - // we have some uninitialized data too - rc = check_address_range(valid_ranges, entry.paddr + entry.filez, entry.vaddr + entry.filez, entry.memsz - entry.filez, true, - ar); - if (rc) return rc; - } + } + if (entry.memsz > entry.filez) { + // we have some uninitialized data too + rc = check_address_range(valid_ranges, entry.paddr + entry.filez, entry.vaddr + entry.filez, entry.memsz - entry.filez, true, + ar); + if (rc) return rc; } } } @@ -242,6 +245,29 @@ static bool is_address_mapped(const std::map& entries, bool *ram_style) { + for(const auto &entry : entries) { + if (entry.type == PT_LOAD && entry.memsz) { + uint mapped_size = std::min(entry.filez, entry.memsz); + if (mapped_size) { + // we back convert the entrypoint from a VADDR to a PADDR to see if it originates in flash, and if + // so call THAT a flash binary. + if (eh.entry >= entry.vaddr && eh.entry < entry.vaddr + mapped_size) { + uint32_t effective_entry = eh.entry + entry.paddr - entry.vaddr; + if (is_address_initialized(rp2040_address_ranges_ram, effective_entry)) { + *ram_style = true; + return 0; + } else if (is_address_initialized(rp2040_address_ranges_flash, effective_entry)) { + *ram_style = false; + return 0; + } + } + } + } + } + return fail(ERROR_INCOMPATIBLE, "entry point is not in mapped part of file"); +} + int elf2uf2(FILE *in, FILE *out) { elf32_header eh; std::map> pages; @@ -249,16 +275,22 @@ int elf2uf2(FILE *in, FILE *out) { bool ram_style = false; address_ranges valid_ranges = {}; if (!rc) { - ram_style = is_address_initialized(rp2040_address_ranges_ram, eh.entry); - if (verbose) { - if (ram_style) { - printf("Detected RAM binary\n"); - } else { - printf("Detected FLASH binary\n"); - } + std::vector entries; + rc = read_elf32_ph_entries(in, eh, entries); + if (!rc) { + rc = determine_binary_type(eh, entries, &ram_style); + } + if (!rc) { + if (verbose) { + if (ram_style) { + printf("Detected RAM binary\n"); + } else { + printf("Detected FLASH binary\n"); + } + } + valid_ranges = ram_style ? rp2040_address_ranges_ram : rp2040_address_ranges_flash; + rc = check_elf32_ph_entries(entries, valid_ranges, pages); } - valid_ranges = ram_style ? rp2040_address_ranges_ram : rp2040_address_ranges_flash; - rc = read_and_check_elf32_ph_entries(in, eh, valid_ranges, pages); } if (rc) return rc; if (pages.empty()) {