Created
January 24, 2023 17:02
-
-
Save matwey/6175accc18b7a6cc0f07c71766cd0ce2 to your computer and use it in GitHub Desktop.
Convert raw AVR binary firmware to ELF format loadable to QEMU
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <errno.h> | |
#include <fcntl.h> | |
#include <sys/stat.h> | |
#include <sys/types.h> | |
#include <unistd.h> | |
#include <sys/mman.h> | |
#include <libelf.h> | |
int main (int argc, char** argv) { | |
if (argc < 2) { | |
fprintf(stderr, "Usage: %s input.bin output.elf\n", argv[0]); | |
return 1; | |
} | |
char* binary = argv[1]; | |
char* filename = argv[2]; | |
struct stat s; | |
int fd_input = open(binary, O_RDONLY); | |
if (fd_input < 0) { | |
fprintf(stderr, "Cannot open file %s: %s\n", binary, strerror(errno)); | |
return 1; | |
} | |
fstat(fd_input, &s); | |
size_t b_size = s.st_size; | |
unsigned char *b_ptr = (unsigned char*) mmap(0, s.st_size, PROT_READ, MAP_PRIVATE, fd_input, 0); | |
if (b_ptr == NULL) { | |
fprintf(stderr, "Cannot read file %s: %s\n", binary, strerror(errno)); | |
return 1; | |
} | |
int fd = open(filename, O_WRONLY | O_CREAT, 0755); | |
if (fd < 0) { | |
fprintf(stderr, "Cannot open file %s: %s\n", filename, strerror(errno)); | |
return 1; | |
} | |
elf_version(EV_CURRENT); | |
Elf *elf = elf_begin(fd, ELF_C_WRITE, NULL); | |
if (elf == NULL) { | |
fprintf(stderr, "Cannot create ELF: %s\n", elf_errmsg(elf_errno())); | |
close(fd); | |
return 1; | |
} | |
Elf32_Ehdr *ehdr = elf32_newehdr(elf); | |
if (ehdr == NULL) { | |
fprintf(stderr, "Cannot create EHDR: %s\n", elf_errmsg(elf_errno())); | |
elf_end(elf); | |
return 1; | |
} | |
ehdr->e_type = ET_EXEC; | |
ehdr->e_machine = EM_AVR; | |
ehdr->e_version = EV_CURRENT; | |
ehdr->e_flags = 0x4; | |
Elf_Scn *text_scn = elf_newscn(elf); | |
if (text_scn == NULL) { | |
fprintf(stderr, "Cannot create .text section: %s\n", elf_errmsg(elf_errno())); | |
elf_end(elf); | |
return 1; | |
} | |
Elf32_Shdr *text = elf32_getshdr(text_scn); | |
if (text == NULL) { | |
fprintf(stderr, "Cannot get .text section: %s\n", elf_errmsg(elf_errno())); | |
elf_end(elf); | |
return 1; | |
} | |
Elf_Data *text_data = elf_newdata(text_scn); | |
if (text_data == NULL) { | |
fprintf(stderr, "Cannot create data for .text section: %s\n", elf_errmsg(elf_errno())); | |
elf_end(elf); | |
return 1; | |
} | |
text_data->d_buf = b_ptr; | |
text_data->d_type = ELF_T_BYTE; | |
text_data->d_size = b_size; | |
text_data->d_align = 1; | |
text_data->d_version = EV_CURRENT; | |
text->sh_name = 1; | |
text->sh_type = SHT_PROGBITS; | |
text->sh_flags = SHF_ALLOC | SHF_EXECINSTR; | |
Elf_Scn *shstrtab_scn = elf_newscn(elf); | |
if (shstrtab_scn == NULL) { | |
fprintf(stderr, "Cannot create .shstrtab section: %s\n", elf_errmsg(elf_errno())); | |
elf_end(elf); | |
return 1; | |
} | |
Elf_Data *strtab_data = elf_newdata(shstrtab_scn); | |
if (strtab_data == NULL) { | |
fprintf(stderr, "Cannot create data for .shstrtab section: %s\n", elf_errmsg(elf_errno())); | |
elf_end(elf); | |
return 1; | |
} | |
char strtab_buf[] = "\0.text\0.shstrtab\0"; | |
strtab_data->d_buf = strtab_buf; | |
strtab_data->d_type = ELF_T_BYTE; | |
strtab_data->d_size = sizeof(strtab_buf) / sizeof(strtab_buf[0]); | |
strtab_data->d_align = 1; | |
strtab_data->d_version = EV_CURRENT; | |
Elf32_Shdr *shstrtab = elf32_getshdr(shstrtab_scn); | |
if (shstrtab == NULL) { | |
fprintf(stderr, "Cannot get .shstrtab section: %s\n", elf_errmsg(elf_errno())); | |
elf_end(elf); | |
return 1; | |
} | |
shstrtab->sh_name = 7; | |
shstrtab->sh_type = SHT_STRTAB; | |
ehdr->e_shstrndx = elf_ndxscn(shstrtab_scn); | |
Elf32_Phdr *phdr = elf32_newphdr(elf, 1); | |
if (phdr == NULL) { | |
fprintf(stderr, "Cannot create PHDR: %s\n", elf_errmsg(elf_errno())); | |
elf_end(elf); | |
return 1; | |
} | |
phdr->p_type = PT_LOAD; | |
phdr->p_vaddr = 0; | |
phdr->p_paddr = 0; | |
phdr->p_flags = PF_R | PF_X; | |
if (elf_update(elf, ELF_C_NULL) < 0) { | |
fprintf(stderr, "Cannot write ELF: %s\n", elf_errmsg(elf_errno())); | |
elf_end(elf); | |
return 1; | |
} | |
phdr->p_offset = text->sh_offset; | |
phdr->p_filesz = text->sh_size; | |
phdr->p_memsz = text->sh_size; | |
if (elf_update(elf, ELF_C_WRITE) < 0) { | |
fprintf(stderr, "Cannot write ELF to disk: %s\n", elf_errmsg(elf_errno())); | |
elf_end(elf); | |
return 1; | |
} | |
elf_end(elf); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment