/*- * Copyright (c) 1999 Stefan Esser * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD: src/usr.sbin/elf2exe/elf2exe.c,v 1.6.2.1 2000/07/20 10:35:23 kris Exp $ * $DragonFly: src/usr.sbin/elf2exe/Attic/elf2exe.c,v 1.2 2003/06/17 04:29:53 dillon Exp $ */ /* * Make an ARC firmware executable from an ELF file. */ #include #include #include #include #include #include #include #include #include #define ALPHA_FMAGIC 0x184 #define TOTHSZ 0x200 typedef struct filehdr { u_int16_t f_magic; u_int16_t f_nscns; u_int32_t f_timdat; u_int32_t f_symptr; u_int32_t f_nsyms; u_int16_t f_opthdr; u_int16_t f_flags; } FILHDR; #define FILHSZ 20 #define ALPHA_AMAGIC 0407 typedef struct aouthdr { u_int16_t a_magic; u_int16_t a_vstamp; u_int32_t a_tsize; u_int32_t a_dsize; u_int32_t a_bsize; u_int32_t a_entry; u_int32_t a_text_start; u_int32_t a_data_start; u_int32_t a_bss_start; u_int32_t a_gprmask; u_int32_t a_cprmask[4]; u_int32_t a_gp_value; } AOUTHDR; #define AOUTSZ 56 typedef struct scnhdr { char s_name[8]; u_int32_t s_fill; u_int32_t s_vaddr; u_int32_t s_size; u_int32_t s_scnptr; u_int32_t s_relptr; u_int32_t s_lnnoptr; u_int16_t s_nreloc; u_int16_t s_nlnno; u_int32_t s_flags; } SCNHDR; #define SCNHSZ 40 #define ROUNDUP(a,b) ((((a) -1) | ((b) -1)) +1) /* * initialization subroutines */ int open_elffile(char *filename) { int fileno = open(filename, O_RDONLY); if (fileno < 0) err(1, "%s", filename); return (fileno); } Elf64_Ehdr * load_ehdr(int fileno) { Elf64_Ehdr *ehdr; size_t bytes = sizeof(*ehdr); ehdr = malloc(bytes); if (ehdr) { lseek(fileno, 0, SEEK_SET); if (read(fileno, ehdr, bytes) != bytes) errx(1, "file truncated (ehdr)"); } return (ehdr); } Elf64_Phdr * load_phdr(int fileno, Elf64_Ehdr *ehdr) { size_t bytes = ehdr->e_phentsize * ehdr->e_phnum; Elf64_Phdr *phdr = malloc(bytes); if (phdr) { lseek(fileno, ehdr->e_phoff, SEEK_SET); if (read(fileno, phdr, bytes) != bytes) errx(1, "file truncated (phdr)"); } return (phdr); } Elf64_Shdr * load_shdr(int fileno, Elf64_Ehdr *ehdr) { size_t bytes = ehdr->e_shentsize * ehdr->e_shnum; Elf64_Shdr *shdr = malloc(bytes); if (shdr) { lseek(fileno, ehdr->e_shoff, SEEK_SET); if (read(fileno, shdr, bytes) != bytes) errx(1, "file truncated (shdr)"); } return (shdr); } char * find_shstrtable(int fileno, int sections, Elf64_Shdr *shdr) { size_t bytes; char *shstrtab = NULL; int i, shstrtabindex; for (i = 0; shstrtab == NULL && i < sections; i++) { if (shdr[i].sh_type == 3 && shdr[i].sh_flags == 0) { shstrtabindex = i; bytes = shdr[shstrtabindex].sh_size; shstrtab = malloc(bytes); if (shstrtab == NULL) errx(1, "malloc failed"); lseek(fileno, shdr[shstrtabindex].sh_offset, SEEK_SET); read(fileno, shstrtab, bytes); if (strcmp (shstrtab + shdr[i].sh_name, ".shstrtab")) { free(shstrtab); shstrtab = NULL; } } } return (shstrtab); } int open_exefile(char *filename) { int fileno = open(filename, O_RDWR | O_TRUNC | O_CREAT, 0666); if (fileno < 0) err(1, "%s", filename); return (fileno); } /* * utility subroutines */ static char *shstrtab; char * section_name(Elf64_Shdr *shdr, int i) { return (shstrtab + shdr[i].sh_name); } int section_index(Elf64_Shdr *shdr, int sections, char *name) { int i; for (i = 0; i < sections; i++) if (strcmp (name, section_name(shdr, i)) == 0) return (i); return (-1); } /* first byte of section */ u_int64_t section_start(Elf64_Shdr *shdr, int sections, char *name) { int i = section_index(shdr, sections, name); if (i < 0) return (-1); return (shdr[i].sh_addr); } /* last byte of section */ u_int64_t section_end(Elf64_Shdr *shdr, int sections, char *name) { int i = section_index(shdr, sections, name); if (i < 0) return (-1); return (shdr[i].sh_addr + shdr[i].sh_size -1); } /* last byte of section */ u_int64_t section_size(Elf64_Shdr *shdr, int sections, char *name) { int i = section_index(shdr, sections, name); if (i < 0) return (-1); return (shdr[i].sh_size); } /* file position of section start */ u_int64_t section_fpos(Elf64_Shdr *shdr, int sections, char *name) { int i = section_index(shdr, sections, name); if (i < 0) return (-1); return (shdr[i].sh_offset); } void usage(void) { fprintf(stderr, "usage: elf2exe infile outfile\n"); exit(1); } int main(int argc, char** argv) { int infd, outfd, i; Elf64_Ehdr *ehdr; Elf64_Phdr *phdr; Elf64_Shdr *shdr; FILHDR filehdr; AOUTHDR aouthdr; SCNHDR textscn, datascn; u_int64_t textstart, textsize, textsize2, textfsize, textfpos; u_int64_t datastart, datasize, datafsize, datafpos; u_int64_t bssstart, bsssize; u_int64_t progentry; char* p; int sections; if (argc != 3) usage(); infd = open_elffile(argv[1]); ehdr = load_ehdr(infd); if (ehdr == NULL) errx(1, "cannot read Elf Header\n"); sections = ehdr->e_shnum; progentry = ehdr->e_entry; phdr = load_phdr(infd, ehdr); shdr = load_shdr(infd, ehdr); outfd = open_exefile(argv[2]); shstrtab = find_shstrtable(infd, sections, shdr); for (i = 1; i < sections; i++) { printf("section %d (%s): " "type=%x flags=0%llx " "offs=%llx size=%llx addr=%llx\n", i, shstrtab + shdr[i].sh_name, shdr[i].sh_type, (long long)shdr[i].sh_flags, (long long)shdr[i].sh_offset, (long long)shdr[i].sh_size, (long long)shdr[i].sh_addr); } textstart = section_start(shdr, sections, ".text"); textsize = section_size(shdr, sections, ".text"); textsize2 = section_end(shdr, sections, ".rodata") - textstart +1; if (textsize < textsize2) textsize = textsize2; textfsize = ROUNDUP(textsize, 512); textfpos = section_fpos(shdr, sections, ".text"); datastart = section_start(shdr, sections, ".data"); datasize = section_start(shdr, sections, ".bss") - datastart; datafsize = ROUNDUP(datasize, 512); datafpos = section_fpos(shdr, sections, ".data"); bssstart = section_start(shdr, sections, ".bss"); bsssize = section_size(shdr, sections, ".bss"); printf("text: %llx(%llx) @%llx data: %llx(%llx) @%llx " "bss: %llx(%llx)\n", (long long)textstart, (long long)textsize, (long long)textfpos, (long long)datastart, (long long)datasize, (long long)datafpos, (long long)bssstart, (long long)bsssize); memset(&filehdr, 0, sizeof filehdr); memset(&aouthdr, 0, sizeof aouthdr); memset(&textscn, 0, sizeof textscn); memset(&datascn, 0, sizeof datascn); filehdr.f_magic = ALPHA_FMAGIC; filehdr.f_nscns = 2; filehdr.f_timdat = time(0); filehdr.f_symptr = 0; filehdr.f_nsyms = 0; filehdr.f_opthdr = AOUTSZ; filehdr.f_flags = 0x010f; aouthdr.a_magic = ALPHA_AMAGIC; aouthdr.a_vstamp = 0x5004; aouthdr.a_tsize = textfsize; aouthdr.a_dsize = datafsize; aouthdr.a_bsize = bsssize; aouthdr.a_entry = progentry; aouthdr.a_text_start = textstart; aouthdr.a_data_start = datastart; aouthdr.a_bss_start = bssstart; strcpy(textscn.s_name, ".text"); textscn.s_fill = textsize; textscn.s_vaddr = textstart; textscn.s_size = textfsize; textscn.s_scnptr = 0x200; textscn.s_relptr = 0; textscn.s_lnnoptr = 0; textscn.s_nreloc = 0; textscn.s_nlnno = 0; textscn.s_flags = 0x20; strcpy(datascn.s_name, ".data"); datascn.s_fill = datasize; datascn.s_vaddr = datastart; datascn.s_size = datafsize; datascn.s_scnptr = 0x200 + textfsize; datascn.s_relptr = 0; datascn.s_lnnoptr = 0; datascn.s_nreloc = 0; datascn.s_nlnno = 0; datascn.s_flags = 0x40; write(outfd, &filehdr, FILHSZ); write(outfd, &aouthdr, AOUTSZ); write(outfd, &textscn, SCNHSZ); write(outfd, &datascn, SCNHSZ); lseek(outfd, textscn.s_scnptr, SEEK_SET); p = malloc(ROUNDUP(textsize, 512)); if (p == NULL) errx(1, "malloc failed"); memset(p, 0, ROUNDUP(textsize, 512)); lseek(infd, textfpos, SEEK_SET); read(infd, p, textsize); write(outfd, p, ROUNDUP(textsize, 512)); free(p); lseek(outfd, datascn.s_scnptr, SEEK_SET); p = malloc(ROUNDUP(datasize, 512)); if (p == NULL) errx(1, "malloc failed"); memset(p, 0, ROUNDUP(datasize, 512)); lseek(infd, datafpos, SEEK_SET); read(infd, p, datasize); write(outfd, p, ROUNDUP(datasize, 512)); free(p); return (0); }