elf2uf2: Use LMA (instead of VMA) of entry_point to determine whether binary is flash/RAM (#1187)

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 @@
     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 @@
     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<uint32_t, std::vector<page_fragment>>& pages) {
+int read_elf32_ph_entries(FILE *in, const elf32_header &eh, std::vector<elf32_ph_entry>& entries) {
     if (eh.ph_entry_size != sizeof(elf32_ph_entry)) {
         return fail(ERROR_FORMAT, "Invalid ELF32 program header");
     }
     if (eh.ph_num) {
-        std::vector<elf32_ph_entry> 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<eh.ph_num;i++) {
-            elf32_ph_entry& entry = entries[i];
-            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");
-                            }
+    }
+    return 0;
+}
+
+int check_elf32_ph_entries(const std::vector<elf32_ph_entry>& entries, const address_ranges& valid_ranges, std::map<uint32_t, std::vector<page_fragment>>& 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 @@
     return true;
 }
 
+static int determine_binary_type(const elf32_header &eh, const std::vector<elf32_ph_entry>& 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<uint32_t, std::vector<page_fragment>> pages;
@@ -249,16 +275,22 @@
     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<elf32_ph_entry> entries;
+        rc = read_elf32_ph_entries(in, eh, entries);
+        if (!rc) {
+            rc = determine_binary_type(eh, entries, &ram_style);
         }
-        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) {
+            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);
+        }
     }
     if (rc) return rc;
     if (pages.empty()) {