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()) {