elf2uf2: Use LMA (instead of VMA) of entry_point to determine whether binary is flash/RAM (#1187)
This commit is contained in:
parent
260df95e44
commit
78d7a2522f
@ -129,7 +129,7 @@ int check_address_range(const address_ranges& valid_ranges, uint32_t addr, uint3
|
|||||||
for(const auto& range : valid_ranges) {
|
for(const auto& range : valid_ranges) {
|
||||||
if (range.from <= addr && range.to >= addr + size) {
|
if (range.from <= addr && range.to >= addr + size) {
|
||||||
if (range.type == address_range::type::NO_CONTENTS && !uninitialized) {
|
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;
|
ar = range;
|
||||||
if (verbose) {
|
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);
|
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)) {
|
if (eh.ph_entry_size != sizeof(elf32_ph_entry)) {
|
||||||
return fail(ERROR_FORMAT, "Invalid ELF32 program header");
|
return fail(ERROR_FORMAT, "Invalid ELF32 program header");
|
||||||
}
|
}
|
||||||
if (eh.ph_num) {
|
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)) {
|
if (fseek(in, eh.ph_offset, SEEK_SET)) {
|
||||||
return fail_read_error();
|
return fail_read_error();
|
||||||
}
|
}
|
||||||
if (eh.ph_num != fread(&entries[0], sizeof(struct elf32_ph_entry), eh.ph_num, in)) {
|
if (eh.ph_num != fread(&entries[0], sizeof(struct elf32_ph_entry), eh.ph_num, in)) {
|
||||||
return fail_read_error();
|
return fail_read_error();
|
||||||
}
|
}
|
||||||
for(uint i=0;i<eh.ph_num;i++) {
|
}
|
||||||
elf32_ph_entry& entry = entries[i];
|
return 0;
|
||||||
if (entry.type == PT_LOAD && entry.memsz) {
|
}
|
||||||
address_range ar;
|
|
||||||
int rc;
|
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) {
|
||||||
uint mapped_size = std::min(entry.filez, entry.memsz);
|
for(const auto & entry : entries) {
|
||||||
if (mapped_size) {
|
if (entry.type == PT_LOAD && entry.memsz) {
|
||||||
rc = check_address_range(valid_ranges, entry.paddr, entry.vaddr, mapped_size, false, ar);
|
address_range ar;
|
||||||
if (rc) return rc;
|
int 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
|
uint mapped_size = std::min(entry.filez, entry.memsz);
|
||||||
if (ar.type != address_range::type::CONTENTS) {
|
if (mapped_size) {
|
||||||
if (verbose) printf(" ignored\n");
|
rc = check_address_range(valid_ranges, entry.paddr, entry.vaddr, mapped_size, false, ar);
|
||||||
continue;
|
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
|
||||||
uint addr = entry.paddr;
|
if (ar.type != address_range::type::CONTENTS) {
|
||||||
uint remaining = mapped_size;
|
if (verbose) printf(" ignored\n");
|
||||||
uint file_offset = entry.offset;
|
continue;
|
||||||
while (remaining) {
|
}
|
||||||
uint off = addr & (PAGE_SIZE - 1);
|
uint addr = entry.paddr;
|
||||||
uint len = std::min(remaining, PAGE_SIZE - off);
|
uint remaining = mapped_size;
|
||||||
auto &fragments = pages[addr - off]; // list of fragments
|
uint file_offset = entry.offset;
|
||||||
// note if filesz is zero, we want zero init which is handled because the
|
while (remaining) {
|
||||||
// statement above creates an empty page fragment list
|
uint off = addr & (PAGE_SIZE - 1);
|
||||||
// check overlap with any existing fragments
|
uint len = std::min(remaining, PAGE_SIZE - off);
|
||||||
for (const auto &fragment : fragments) {
|
auto &fragments = pages[addr - off]; // list of fragments
|
||||||
if ((off < fragment.page_offset + fragment.bytes) !=
|
// note if filesz is zero, we want zero init which is handled because the
|
||||||
((off + len) <= fragment.page_offset)) {
|
// statement above creates an empty page fragment list
|
||||||
fail(ERROR_FORMAT, "In memory segments overlap");
|
// 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
|
if (entry.memsz > entry.filez) {
|
||||||
rc = check_address_range(valid_ranges, entry.paddr + entry.filez, entry.vaddr + entry.filez, entry.memsz - entry.filez, true,
|
// we have some uninitialized data too
|
||||||
ar);
|
rc = check_address_range(valid_ranges, entry.paddr + entry.filez, entry.vaddr + entry.filez, entry.memsz - entry.filez, true,
|
||||||
if (rc) return rc;
|
ar);
|
||||||
}
|
if (rc) return rc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -242,6 +245,29 @@ static bool is_address_mapped(const std::map<uint32_t, std::vector<page_fragment
|
|||||||
return true;
|
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) {
|
int elf2uf2(FILE *in, FILE *out) {
|
||||||
elf32_header eh;
|
elf32_header eh;
|
||||||
std::map<uint32_t, std::vector<page_fragment>> pages;
|
std::map<uint32_t, std::vector<page_fragment>> pages;
|
||||||
@ -249,16 +275,22 @@ int elf2uf2(FILE *in, FILE *out) {
|
|||||||
bool ram_style = false;
|
bool ram_style = false;
|
||||||
address_ranges valid_ranges = {};
|
address_ranges valid_ranges = {};
|
||||||
if (!rc) {
|
if (!rc) {
|
||||||
ram_style = is_address_initialized(rp2040_address_ranges_ram, eh.entry);
|
std::vector<elf32_ph_entry> entries;
|
||||||
if (verbose) {
|
rc = read_elf32_ph_entries(in, eh, entries);
|
||||||
if (ram_style) {
|
if (!rc) {
|
||||||
printf("Detected RAM binary\n");
|
rc = determine_binary_type(eh, entries, &ram_style);
|
||||||
} else {
|
}
|
||||||
printf("Detected FLASH binary\n");
|
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 (rc) return rc;
|
||||||
if (pages.empty()) {
|
if (pages.empty()) {
|
||||||
|
Loading…
Reference in New Issue
Block a user