/* $OpenBSD$ */ /* * Copyright (c) 2004 Dale Rahn * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * This program is a kludge to get around the broken objcopy which * will not correctly copy an i386 ELF kernel to a.out format for * pre 3.4 bootloader */ #include #include #include #include #include #include #include #include #include #include extern char *__progname; /* * these constants are i386 specific, if ported to additional architectures * this should be appropriately ifdef'd. */ #define KERNEL_MASK ~0xf0000000 #define KERNEL_SHIFT -0x00100000 int main(int argc, char **argv) { struct stat sb; Elf_Ehdr *ehdr; Elf_Phdr *phdr; Elf_Shdr *shdr; Elf_Addr s; vaddr_t max_file; vaddr_t max_addr; vaddr_t writeable_base; off_t off; void *sbase; int sfd; int dfd; int i; struct exec aout; char zero; if (argc != 3) { printf("USAGE: %s ", __progname); return 1; } sfd = open(argv[1], O_RDONLY, 0755); if (sfd == -1) err(1, "unable to open %s", argv[1]); if (fstat(sfd, &sb) < 0) err(2, "fstat"); if (sb.st_size < sizeof (Elf_Ehdr)) err(1, "truncated src file %s", argv[1]); sbase = mmap(0, sb.st_size, PROT_READ, MAP_FILE, sfd, 0); if (sbase == MAP_FAILED) err(1, "unable to mmap file %s", argv[1]); ehdr = (Elf_Ehdr *)sbase; phdr = (Elf_Phdr *)((char *)ehdr + ehdr->e_phoff); max_file = 0; max_addr= 0; for (i = 0; i < ehdr->e_phnum; i++) { switch (phdr[i].p_type) { case PT_LOAD: printf("looking at phdr %d %x, %x, %x, %x , %x ali %x\n", i, phdr[i].p_vaddr, phdr[i].p_filesz, phdr[i].p_memsz, phdr[i].p_vaddr + phdr[i].p_filesz, phdr[i].p_vaddr + phdr[i].p_memsz, phdr[i].p_align ); s = phdr[i].p_vaddr + phdr[i].p_filesz; s += PAGE_MASK; s &= ~PAGE_MASK; s &= KERNEL_MASK; if (max_file < s) max_file = s; s = phdr[i].p_vaddr + phdr[i].p_memsz; s += PAGE_MASK; s &= ~PAGE_MASK; s &= KERNEL_MASK; if (max_addr < s) max_addr = s; break; default: break; } } dfd = open(argv[2], O_CREAT|O_TRUNC|O_RDWR, 0755); if (dfd == -1) err(1, "unable to open %s for writing", argv[2]); printf("max file %x, max_addr %x\n", max_file, max_addr); off = max_file; if (lseek(dfd, off-1, SEEK_SET) != off-1) err(1, "lseek error on %s", argv[2]); zero = 0; if (write(dfd, &zero, 1) != 1) err(1, "write error on %s", argv[2]); for (i = 0; i < ehdr->e_phnum; i++) { switch (phdr[i].p_type) { case PT_LOAD: off = phdr[i].p_vaddr; off &= KERNEL_MASK; off += KERNEL_SHIFT; printf("writing to %llx, %x\n", off, phdr[i].p_filesz); if (lseek(dfd, off, SEEK_SET) != off) err(1, "lseek error on %s", argv[2]); if (write(dfd, sbase + phdr[i].p_offset, phdr[i].p_filesz) != phdr[i].p_filesz) err(1, "write error on %s", argv[2]); break; default: break; } } off = 0; if (lseek(dfd, off, SEEK_SET) != off) err(1, "lseek error on %s", argv[2]); shdr = (Elf_Shdr *)((char *)ehdr + ehdr->e_shoff); for (i = 0; i < ehdr->e_shnum; i++) { if (shdr[i].sh_flags & SHF_EXECINSTR) { printf("looking at section %d %x %x\n", i, shdr[i].sh_addr ); writeable_base = (shdr[i].sh_addr + shdr[i].sh_size) & ~PAGE_MASK; writeable_base &= KERNEL_MASK; break; } } printf("max file %x, max_addr %x writeable_base %x\n", max_file, max_addr, writeable_base); N_SETMAGIC(aout,ZMAGIC,MID_MACHINE,0); printf("aout.a_midmag %x\n", aout.a_midmag); aout.a_entry = ehdr->e_entry & KERNEL_MASK; printf("aout.a_entry %x\n", aout.a_entry); aout.a_text = writeable_base - (aout.a_entry & ~PAGE_MASK); printf("aout.a_text %x\n", aout.a_text); aout.a_data = max_file - writeable_base; printf("aout.a_data %x\n", aout.a_data); aout.a_bss = max_addr - max_file; printf("aout.a_bss %x\n", aout.a_bss); aout.a_syms = 0; aout.a_trsize = 0; aout.a_drsize = 0; write(dfd, &aout, sizeof (aout)); return 0; }