/* * Elf binaries. */ static int elfdotout(int fd, Fhdr *fp, ExecHdr *hp) { Ehdr *ep; /* bitswap the header according to the DATA format */ ep = &hp->e; if(ep->ident[CLASS] == ELFCLASS32) return elf32dotout(fd, fp, hp); else if(ep->ident[CLASS] == ELFCLASS64) return elf64dotout(fd, fp, hp); werrstr("bad ELF class - not 32 bit"); return 0; }
static int elfdotout(int fd, Fhdr *fp, ExecHdr *hp) { uint32 (*swal)(uint32); ushort (*swab)(ushort); Ehdr32 *ep; Phdr32 *ph; int i, it, id, is, phsz, shsz; Shdr32 *sh; /* bitswap the header according to the DATA format */ ep = &hp->e.elfhdr32; if(ep->ident[CLASS] != ELFCLASS32) { return elf64dotout(fd, fp, hp); } if(ep->ident[DATA] == ELFDATA2LSB) { swab = leswab; swal = leswal; } else if(ep->ident[DATA] == ELFDATA2MSB) { swab = beswab; swal = beswal; } else { werrstr("bad ELF encoding - not big or little endian"); return 0; } ep->type = swab(ep->type); ep->machine = swab(ep->machine); ep->version = swal(ep->version); ep->elfentry = swal(ep->elfentry); ep->phoff = swal(ep->phoff); ep->shoff = swal(ep->shoff); ep->flags = swal(ep->flags); ep->ehsize = swab(ep->ehsize); ep->phentsize = swab(ep->phentsize); ep->phnum = swab(ep->phnum); ep->shentsize = swab(ep->shentsize); ep->shnum = swab(ep->shnum); ep->shstrndx = swab(ep->shstrndx); if(ep->type != EXEC || ep->version != CURRENT) return 0; /* we could definitely support a lot more machines here */ fp->magic = ELF_MAG; fp->hdrsz = (ep->ehsize+ep->phnum*ep->phentsize+16)&~15; switch(ep->machine) { case I386: mach = &mi386; fp->type = FI386; break; case MIPS: mach = &mmips; fp->type = FMIPS; break; case SPARC64: mach = &msparc64; fp->type = FSPARC64; break; case POWER: mach = &mpower; fp->type = FPOWER; break; case ARM: mach = &marm; fp->type = FARM; break; default: return 0; } if(ep->phentsize != sizeof(Phdr32)) { werrstr("bad ELF header size"); return 0; } phsz = sizeof(Phdr32)*ep->phnum; ph = malloc(phsz); if(!ph) return 0; seek(fd, ep->phoff, 0); if(read(fd, ph, phsz) < 0) { free(ph); return 0; } hswal(ph, phsz/sizeof(uint32), swal); shsz = sizeof(Shdr32)*ep->shnum; sh = malloc(shsz); if(sh) { seek(fd, ep->shoff, 0); if(read(fd, sh, shsz) < 0) { free(sh); sh = 0; } else hswal(sh, shsz/sizeof(uint32), swal); } /* find text, data and symbols and install them */ it = id = is = -1; for(i = 0; i < ep->phnum; i++) { if(ph[i].type == LOAD && (ph[i].flags & (R|X)) == (R|X) && it == -1) it = i; else if(ph[i].type == LOAD && (ph[i].flags & (R|W)) == (R|W) && id == -1) id = i; else if(ph[i].type == NOPTYPE && is == -1) is = i; } if(it == -1 || id == -1) { /* * The SPARC64 boot image is something of an ELF hack. * Text+Data+BSS are represented by ph[0]. Symbols * are represented by ph[1]: * * filesz, memsz, vaddr, paddr, off * ph[0] : txtsz+datsz, txtsz+datsz+bsssz, txtaddr-KZERO, datasize, txtoff * ph[1] : symsz, lcsz, 0, 0, symoff */ if(ep->machine == SPARC64 && ep->phnum == 2) { uint32 txtaddr, txtsz, dataddr, bsssz; txtaddr = ph[0].vaddr | 0x80000000; txtsz = ph[0].filesz - ph[0].paddr; dataddr = txtaddr + txtsz; bsssz = ph[0].memsz - ph[0].filesz; settext(fp, ep->elfentry | 0x80000000, txtaddr, txtsz, ph[0].offset); setdata(fp, dataddr, ph[0].paddr, ph[0].offset + txtsz, bsssz); setsym(fp, ph[1].filesz, 0, ph[1].memsz, ph[1].offset); free(ph); return 1; } werrstr("No TEXT or DATA sections"); error: free(sh); free(ph); return 0; } settext(fp, ep->elfentry, ph[it].vaddr, ph[it].memsz, ph[it].offset); setdata(fp, ph[id].vaddr, ph[id].filesz, ph[id].offset, ph[id].memsz - ph[id].filesz); if(is != -1) setsym(fp, ph[is].filesz, 0, ph[is].memsz, ph[is].offset); else if(sh != 0){ char *buf; uvlong symsize = 0; uvlong symoff = 0; uvlong pclnsz = 0; /* load shstrtab names */ buf = malloc(sh[ep->shstrndx].size); if (buf == 0) goto done; memset(buf, 0, sizeof buf); seek(fd, sh[ep->shstrndx].offset, 0); read(fd, buf, sh[ep->shstrndx].size); for(i = 0; i < ep->shnum; i++) { if (strcmp(&buf[sh[i].name], ".gosymtab") == 0) { symsize = sh[i].size; symoff = sh[i].offset; } if (strcmp(&buf[sh[i].name], ".gopclntab") == 0) { if (sh[i].offset != symoff+symsize) { werrstr("pc line table not contiguous with symbol table"); free(buf); goto error; } pclnsz = sh[i].size; } } setsym(fp, symsize, 0, pclnsz, symoff); free(buf); } done: free(sh); free(ph); return 1; }