X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/47c4e0c19ae8526b14ce4e0d7b243f7a4dc6fafd..bffa3430fbbaaad29bec0b5bee9c1f0bfc7fd068:/lunaix-os/scripts/elftool.c?ds=sidebyside diff --git a/lunaix-os/scripts/elftool.c b/lunaix-os/scripts/elftool.c new file mode 100644 index 0000000..db24ed7 --- /dev/null +++ b/lunaix-os/scripts/elftool.c @@ -0,0 +1,342 @@ +#include +#include +#include +#include +#include +#include +#include + +typedef unsigned long elf64_ptr_t; +typedef unsigned short elf64_hlf_t; +typedef unsigned long elf64_off_t; +typedef int elf64_swd_t; +typedef unsigned int elf64_wrd_t; +typedef unsigned long elf64_xwrd_t; +typedef long elf64_sxwrd_t; + +typedef unsigned int elf32_ptr_t; +typedef unsigned short elf32_hlf_t; +typedef unsigned int elf32_off_t; +typedef unsigned int elf32_swd_t; +typedef unsigned int elf32_wrd_t; + +#define ELFCLASS32 1 +#define ELFCLASS64 2 + +#define PT_LOAD 1 + +typedef unsigned long ptr_t; + +struct elf_generic_ehdr +{ + union { + struct { + unsigned int signature; + unsigned char class; + } __attribute__((packed)); + unsigned char e_ident[16]; + }; + unsigned short e_type; + unsigned short e_machine; + unsigned int e_version; +}; + +struct elf32_ehdr +{ + struct elf_generic_ehdr head; + elf32_ptr_t e_entry; + elf32_off_t e_phoff; + elf32_off_t e_shoff; + elf32_wrd_t e_flags; + elf32_hlf_t e_ehsize; + elf32_hlf_t e_phentsize; + elf32_hlf_t e_phnum; + elf32_hlf_t e_shentsize; + elf32_hlf_t e_shnum; + elf32_hlf_t e_shstrndx; +}; + +struct elf64_ehdr +{ + struct elf_generic_ehdr head; + elf64_ptr_t e_entry; + elf64_off_t e_phoff; + elf64_off_t e_shoff; + elf64_wrd_t e_flags; + elf64_hlf_t e_ehsize; + elf64_hlf_t e_phentsize; + elf64_hlf_t e_phnum; + elf64_hlf_t e_shentsize; + elf64_hlf_t e_shnum; + elf64_hlf_t e_shstrndx; +}; + +struct elf64_phdr +{ + elf64_wrd_t p_type; + elf64_wrd_t p_flags; + elf64_off_t p_offset; + elf64_ptr_t p_va; + elf64_ptr_t p_pa; + elf64_xwrd_t p_filesz; + elf64_xwrd_t p_memsz; + elf64_xwrd_t p_align; +}; + +struct elf32_phdr +{ + elf32_wrd_t p_type; + elf32_off_t p_offset; + elf32_ptr_t p_va; + elf32_ptr_t p_pa; + elf32_wrd_t p_filesz; + elf32_wrd_t p_memsz; + elf32_wrd_t p_flags; + elf32_wrd_t p_align; +}; + +struct elf_section +{ + ptr_t va; + ptr_t pa; + unsigned int flags; + unsigned int memsz; +}; + +struct ksec_genctx +{ + struct elf_section* secs; + int size; + const char* prefix; +}; + +#define MAPPED_SIZE (256 << 10) + +static struct elf_generic_ehdr* +__load_elf(const char* path) +{ + int fd; + struct elf_generic_ehdr* ehdr; + + fd = open(path, O_RDONLY); + if (fd == -1) { + printf("fail to open elf: %s\n", strerror(errno)); + return NULL; + } + + ehdr = mmap(NULL, MAPPED_SIZE, PROT_READ, MAP_SHARED, fd, 0); + if ((void*)ehdr == (void*)-1) { + printf("fail to mmap elf (%d): %s\n", errno, strerror(errno)); + return NULL; + } + + return ehdr; +} + +static void +__wr_mapentry(struct ksec_genctx* ctx, struct elf_section* sec) +{ + printf("/* --- entry --- */\n"); + printf("%s 0x%lx\n", ctx->prefix, sec->va); + printf("%s 0x%lx\n", ctx->prefix, sec->pa); + printf(".4byte 0x%x\n", sec->memsz); + printf(".4byte 0x%x\n", sec->flags); +} + +static void +__wr_maplast(struct ksec_genctx* ctx, struct elf_section* sec) +{ + printf("/* --- entry --- */\n"); + printf("%s 0x%lx\n", ctx->prefix, sec->va); + printf("%s 0x%lx\n", ctx->prefix, sec->pa); + printf(".4byte (__kexec_end - 0x%lx)\n", sec->va); + printf(".4byte 0x%x\n", sec->flags); +} + +#define SIZEPF32 ".4byte" +#define SIZEPF64 ".8byte" +#define gen_ksec_map(bits, ctx, ehdr) \ + ({ \ + struct elf##bits##_ehdr *_e; \ + struct elf##bits##_phdr *phdr, *phent; \ + _e = (struct elf##bits##_ehdr*)(ehdr); \ + phdr = (struct elf##bits##_phdr*)((ptr_t)_e + _e->e_phoff); \ + for (int i = 0, j = 0; i < _e->e_phnum; i++) { \ + phent = &phdr[i]; \ + if (phent->p_type != PT_LOAD) { \ + continue; \ + } \ + ctx.secs[j++] = (struct elf_section) { \ + .va = phent->p_va, \ + .pa = phent->p_pa, \ + .memsz = phent->p_memsz, \ + .flags = phent->p_flags, \ + }; \ + } \ + }) + +#define count_loadable(bits, ehdr) \ + ({ \ + struct elf##bits##_ehdr *_e; \ + struct elf##bits##_phdr *phdr, *phent; \ + int all_loadable = 0; \ + _e = (struct elf##bits##_ehdr*)(ehdr); \ + phdr = (struct elf##bits##_phdr*)((ptr_t)_e + _e->e_phoff); \ + for (int i = 0; i < _e->e_phnum; i++) { \ + phent = &phdr[i]; \ + if (phent->p_type == PT_LOAD) { \ + all_loadable++; \ + } \ + } \ + all_loadable; \ + }) + +static void +__emit_size(struct ksec_genctx* genctx) +{ + ptr_t va; + unsigned int size = 0; + int n = genctx->size - 1; + + /* + first two LOAD are boot text and data. + we are calculating the kernel size, so + ignore it. + */ + for (int i = 2; i < n; i++) + { + size += genctx->secs[i].memsz; + } + + va = genctx->secs[n].va; + printf(".4byte 0x%x + (__kexec_end - 0x%lx)\n", size, va); +} + +static void +__generate_kernelmap(struct elf_generic_ehdr* ehdr) +{ + + printf(".section .autogen.ksecmap, \"a\", @progbits\n" + ".global __autogen_ksecmap\n" + "__autogen_ksecmap:\n"); + + struct ksec_genctx genctx; + + if (ehdr->class == ELFCLASS32) { + genctx.size = count_loadable(32, ehdr); + genctx.prefix = SIZEPF32; + } else { + genctx.size = count_loadable(64, ehdr); + genctx.prefix = SIZEPF64; + } + + genctx.secs = calloc(genctx.size, sizeof(struct elf_section)); + + if (ehdr->class == ELFCLASS32) { + gen_ksec_map(32, genctx, ehdr); + } + else { + genctx.size = count_loadable(64, ehdr); + gen_ksec_map(64, genctx, ehdr); + } + + int i = 0; + struct elf_section* sec_ent; + + printf(".4byte 0x%x\n", genctx.size); + __emit_size(&genctx); + + /* + Lunaix define the last LOAD phdr is variable + sized. that is the actual size will not be known + until after relink, so we need to emit a special + entry and let linker determine the size. + (see __wr_maplast) + */ + + for (; i < genctx.size - 1; i++) + { + sec_ent = &genctx.secs[i]; + __wr_mapentry(&genctx, sec_ent); + } + + __wr_maplast(&genctx, &genctx.secs[i]); +} + +#define MODE_GETARCH 1 +#define MODE_GENLOAD 2 +#define MODE_ERROR 3 + +int +main(int argc, char* const* argv) +{ + int c, mode; + char *path, *out; + + path = NULL; + mode = MODE_GETARCH; + + while ((c = getopt(argc, argv, "i:tph")) != -1) + { + switch (c) + { + case 'i': + path = optarg; + break; + + case 't': + mode = MODE_GETARCH; + break; + + case 'p': + mode = MODE_GENLOAD; + break; + + case 'h': + printf("usage: elftool -i elf_file -pt [-o out]\n"); + printf(" -t: get elf type.\n"); + printf(" -p: generate load sections.\n"); + exit(1); + break; + + default: + printf("unknown option: '%c'", optopt); + exit(1); + break; + } + } + + if (!path) { + printf("must specify an elf.\n"); + exit(1); + } + + struct elf_generic_ehdr* ehdr; + ehdr = __load_elf(path); + + if (!ehdr) { + return 1; + } + + if (ehdr->signature != 0x464c457fU) { + printf("not an elf file\n"); + return 1; + } + + if (mode == MODE_GETARCH) { + if (ehdr->class == ELFCLASS32) { + printf("ELF32\n"); + } + else { + printf("ELF64\n"); + } + return 0; + } + + if (mode == MODE_GENLOAD) { + __generate_kernelmap(ehdr); + return 0; + } + + return 0; +} \ No newline at end of file