/* * ELF64 binaries. */ static int elf64dotout(int fd, Fhdr *fp, ExecHdr *hp) { E64hdr *ep; P64hdr *ph; ushort (*swab)(ushort); ulong (*swal)(ulong); uvlong (*swav)(uvlong); int i, it, id, is, phsz; uvlong uvl; ep = &hp->e; if(ep->ident[DATA] == ELFDATA2LSB) { swab = leswab; swal = leswal; swav = leswav; } else if(ep->ident[DATA] == ELFDATA2MSB) { swab = beswab; swal = beswal; swav = beswav; } else { werrstr("bad ELF64 encoding - not big or little endian"); return 0; } ep->type = swab(ep->type); ep->machine = swab(ep->machine); ep->version = swal(ep->version); if(ep->type != EXEC || ep->version != CURRENT) return 0; ep->elfentry = swav(ep->elfentry); ep->phoff = swav(ep->phoff); ep->shoff = swav(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); fp->magic = ELF_MAG; fp->hdrsz = (ep->ehsize+ep->phnum*ep->phentsize+16)&~15; switch(ep->machine) { default: return 0; case AMD64: mach = &mamd64; fp->type = FAMD64; fp->name = "amd64 ELF64 executable"; break; case POWER64: mach = &mpower64; fp->type = FPOWER64; fp->name = "power64 ELF64 executable"; break; } if(ep->phentsize != sizeof(P64hdr)) { werrstr("bad ELF64 header size"); return 0; } phsz = sizeof(P64hdr)*ep->phnum; ph = malloc(phsz); if(!ph) return 0; seek(fd, ep->phoff, 0); if(read(fd, ph, phsz) < 0) { free(ph); return 0; } for(i = 0; i < ep->phnum; i++) { ph[i].type = swal(ph[i].type); ph[i].flags = swal(ph[i].flags); ph[i].offset = swav(ph[i].offset); ph[i].vaddr = swav(ph[i].vaddr); ph[i].paddr = swav(ph[i].paddr); ph[i].filesz = swav(ph[i].filesz); ph[i].memsz = swav(ph[i].memsz); ph[i].align = swav(ph[i].align); } /* 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) { werrstr("No ELF64 TEXT or DATA sections"); free(ph); return 0; } settext(fp, ep->elfentry, ph[it].vaddr, ph[it].memsz, ph[it].offset); /* 8c: out of fixed registers */ uvl = ph[id].memsz - ph[id].filesz; setdata(fp, ph[id].vaddr, ph[id].filesz, ph[id].offset, uvl); if(is != -1) setsym(fp, ph[is].filesz, 0, ph[is].memsz, ph[is].offset); free(ph); return 1; }
static int machdotout(int fd, Fhdr *fp, ExecHdr *hp) { uvlong (*swav)(uvlong); uint32 (*swal)(uint32); ushort (*swab)(ushort); Machhdr *mp; MachCmd **cmd; MachSymSeg *symtab; MachSymSeg *pclntab; MachSeg64 *seg; MachSect64 *sect; MachSeg32 *seg32; MachSect32 *sect32; uvlong textsize, datasize, bsssize; uchar *cmdbuf; uchar *cmdp; int i, hdrsize; uint32 textva, textoff, datava, dataoff; mp = &hp->e.machhdr; if (leswal(mp->filetype) != MACH_EXECUTABLE_TYPE) { werrstr("bad MACH executable type %#ux", leswal(mp->filetype)); return 0; } swab = leswab; swal = leswal; swav = leswav; mp->magic = swal(mp->magic); mp->cputype = swal(mp->cputype); mp->cpusubtype = swal(mp->cpusubtype); mp->filetype = swal(mp->filetype); mp->ncmds = swal(mp->ncmds); mp->sizeofcmds = swal(mp->sizeofcmds); mp->flags = swal(mp->flags); mp->reserved = swal(mp->reserved); hdrsize = 0; switch(mp->magic) { case 0xFEEDFACE: // 32-bit mach if (mp->cputype != MACH_CPU_TYPE_X86) { werrstr("bad MACH cpu type - not 386"); return 0; } if (mp->cpusubtype != MACH_CPU_SUBTYPE_X86) { werrstr("bad MACH cpu subtype - not 386"); return 0; } if (mp->filetype != MACH_EXECUTABLE_TYPE) { werrstr("bad MACH executable type"); return 0; } mach = &mi386; fp->type = FI386; hdrsize = 28; break; case 0xFEEDFACF: // 64-bit mach if (mp->cputype != MACH_CPU_TYPE_X86_64) { werrstr("bad MACH cpu type - not amd64"); return 0; } if (mp->cpusubtype != MACH_CPU_SUBTYPE_X86) { werrstr("bad MACH cpu subtype - not amd64"); return 0; } mach = &mamd64; fp->type = FAMD64; hdrsize = 32; break; default: werrstr("not mach %#ux", mp->magic); return 0; } cmdbuf = malloc(mp->sizeofcmds); seek(fd, hdrsize, 0); if(read(fd, cmdbuf, mp->sizeofcmds) != mp->sizeofcmds) { free(cmdbuf); return 0; } cmd = malloc(mp->ncmds * sizeof(MachCmd*)); cmdp = cmdbuf; textva = 0; textoff = 0; dataoff = 0; datava = 0; symtab = 0; pclntab = 0; textsize = datasize = bsssize = 0; for (i = 0; i < mp->ncmds; i++) { MachCmd *c; cmd[i] = (MachCmd*)cmdp; c = cmd[i]; c->type = swal(c->type); c->size = swal(c->size); switch(c->type) { case MACH_SEGMENT_32: if(mp->magic != 0xFEEDFACE) { werrstr("segment 32 in mach 64"); goto bad; } seg32 = (MachSeg32*)c; seg32->vmaddr = swav(seg32->vmaddr); seg32->vmsize = swav(seg32->vmsize); seg32->fileoff = swav(seg32->fileoff); seg32->filesize = swav(seg32->filesize); seg32->maxprot = swal(seg32->maxprot); seg32->initprot = swal(seg32->initprot); seg32->nsects = swal(seg32->nsects); seg32->flags = swal(seg32->flags); if (strcmp(seg32->segname, "__TEXT") == 0) { textva = seg32->vmaddr; textoff = seg32->fileoff; sect32 = (MachSect32*)(cmdp + sizeof(MachSeg32)); if (strcmp(sect32->sectname, "__text") == 0) { textsize = swal(sect32->size); } else { werrstr("no text section"); goto bad; } } if (strcmp(seg32->segname, "__DATA") == 0) { datava = seg32->vmaddr; dataoff = seg32->fileoff; sect32 = (MachSect32*)(cmdp + sizeof(MachSeg32)); if (strcmp(sect32->sectname, "__data") == 0) { datasize = swal(sect32->size); } else { werrstr("no data section"); goto bad; } sect32++; if (strcmp(sect32->sectname, "__nl_symbol_ptr") == 0) sect32++; if (strcmp(sect32->sectname, "__bss") == 0) { bsssize = swal(sect32->size); } else { werrstr("no bss section"); goto bad; } } break; case MACH_SEGMENT_64: if(mp->magic != 0xFEEDFACF) { werrstr("segment 32 in mach 64"); goto bad; } seg = (MachSeg64*)c; seg->vmaddr = swav(seg->vmaddr); seg->vmsize = swav(seg->vmsize); seg->fileoff = swav(seg->fileoff); seg->filesize = swav(seg->filesize); seg->maxprot = swal(seg->maxprot); seg->initprot = swal(seg->initprot); seg->nsects = swal(seg->nsects); seg->flags = swal(seg->flags); if (strcmp(seg->segname, "__TEXT") == 0) { textva = seg->vmaddr; textoff = seg->fileoff; sect = (MachSect64*)(cmdp + sizeof(MachSeg64)); if (strcmp(sect->sectname, "__text") == 0) { textsize = swav(sect->size); } else { werrstr("no text section"); goto bad; } } if (strcmp(seg->segname, "__DATA") == 0) { datava = seg->vmaddr; dataoff = seg->fileoff; sect = (MachSect64*)(cmdp + sizeof(MachSeg64)); if (strcmp(sect->sectname, "__data") == 0) { datasize = swav(sect->size); } else { werrstr("no data section"); goto bad; } sect++; if (strcmp(sect->sectname, "__bss") == 0) { bsssize = swav(sect->size); } else { werrstr("no bss section"); goto bad; } } break; case MACH_UNIXTHREAD: break; case MACH_SYMSEG: if (symtab == 0) symtab = (MachSymSeg*)c; else if (pclntab == 0) pclntab = (MachSymSeg*)c; break; } cmdp += c->size; } if (textva == 0 || datava == 0) { free(cmd); free(cmdbuf); return 0; } /* compute entry by taking address after header - weird - BUG? */ settext(fp, textva+sizeof(Machhdr) + mp->sizeofcmds, textva, textsize, textoff); setdata(fp, datava, datasize, dataoff, bsssize); if(symtab != 0) setsym(fp, symtab->filesize, 0, pclntab? pclntab->filesize : 0, symtab->fileoff); free(cmd); free(cmdbuf); return 1; bad: free(cmd); free(cmdbuf); return 0; }
static int machdotout(int fd, Fhdr *fp, ExecHdr *hp) { uvlong (*swav)(uvlong); uint32 (*swal)(uint32); Machhdr *mp; MachCmd **cmd; MachSymSeg *symtab; MachSymSeg *pclntab; MachSeg64 *seg; MachSect64 *sect; MachSeg32 *seg32; MachSect32 *sect32; uvlong textsize, datasize, bsssize; uchar *cmdbuf; uchar *cmdp; int i, j, hdrsize; uint32 textva, textoff, datava, dataoff, symoff, symsize, pclnoff, pclnsize; mp = &hp->e.machhdr; if (leswal(mp->filetype) != MACH_EXECUTABLE_TYPE) { werrstr("bad MACH executable type %#ux", leswal(mp->filetype)); return 0; } swal = leswal; swav = leswav; mp->magic = swal(mp->magic); mp->cputype = swal(mp->cputype); mp->cpusubtype = swal(mp->cpusubtype); mp->filetype = swal(mp->filetype); mp->ncmds = swal(mp->ncmds); mp->sizeofcmds = swal(mp->sizeofcmds); mp->flags = swal(mp->flags); mp->reserved = swal(mp->reserved); switch(mp->magic) { case 0xFEEDFACE: // 32-bit mach if (mp->cputype != MACH_CPU_TYPE_X86) { werrstr("bad MACH cpu type - not 386"); return 0; } if (mp->cpusubtype != MACH_CPU_SUBTYPE_X86) { werrstr("bad MACH cpu subtype - not 386"); return 0; } if (mp->filetype != MACH_EXECUTABLE_TYPE) { werrstr("bad MACH executable type"); return 0; } mach = &mi386; fp->type = FI386; hdrsize = 28; break; case 0xFEEDFACF: // 64-bit mach werrstr("64 bit mach NOT SUPPORTED"); return 0; //if (mp->cputype != MACH_CPU_TYPE_X86_64) { // werrstr("bad MACH cpu type - not amd64"); // return 0; //} // //if (mp->cpusubtype != MACH_CPU_SUBTYPE_X86 && mp->cpusubtype != MACH_CPU_SUBTYPE_X86_64) { // werrstr("bad MACH cpu subtype - not amd64"); // return 0; //} //mach = &mamd64; //fp->type = FAMD64; //hdrsize = 32; //break; default: werrstr("not mach %#ux", mp->magic); return 0; } cmdbuf = malloc(mp->sizeofcmds); if(!cmdbuf) { werrstr("out of memory"); return 0; } seek(fd, hdrsize, 0); if(read(fd, cmdbuf, mp->sizeofcmds) != mp->sizeofcmds) { free(cmdbuf); return 0; } cmd = malloc(mp->ncmds * sizeof(MachCmd*)); if(!cmd) { free(cmdbuf); werrstr("out of memory"); return 0; } cmdp = cmdbuf; textva = 0; textoff = 0; dataoff = 0; datava = 0; symtab = 0; pclntab = 0; textsize = 0; datasize = 0; bsssize = 0; symoff = 0; symsize = 0; pclnoff = 0; pclnsize = 0; for (i = 0; i < mp->ncmds; i++) { MachCmd *c; cmd[i] = (MachCmd*)cmdp; c = cmd[i]; c->type = swal(c->type); c->size = swal(c->size); switch(c->type) { case MACH_SEGMENT_32: if(mp->magic != 0xFEEDFACE) { werrstr("segment 32 in mach 64"); goto bad; } seg32 = (MachSeg32*)c; seg32->vmaddr = swav(seg32->vmaddr); seg32->vmsize = swav(seg32->vmsize); seg32->fileoff = swav(seg32->fileoff); seg32->filesize = swav(seg32->filesize); seg32->maxprot = swal(seg32->maxprot); seg32->initprot = swal(seg32->initprot); seg32->nsects = swal(seg32->nsects); seg32->flags = swal(seg32->flags); if (strcmp(seg32->segname, "__TEXT") == 0) { textva = seg32->vmaddr; textoff = seg32->fileoff; textsize = seg32->vmsize; sect32 = (MachSect32*)(cmdp + sizeof(MachSeg32)); for(j = 0; j < seg32->nsects; j++, sect32++) { if (strcmp(sect32->sectname, "__gosymtab") == 0) { symoff = swal(sect32->offset); symsize = swal(sect32->size); } if (strcmp(sect32->sectname, "__gopclntab") == 0) { pclnoff = swal(sect32->offset); pclnsize = swal(sect32->size); } } } if (strcmp(seg32->segname, "__DATA") == 0) { datava = seg32->vmaddr; dataoff = seg32->fileoff; datasize = seg32->filesize; bsssize = seg32->vmsize - seg32->filesize; } break; case MACH_SEGMENT_64: werrstr("MACH SEGMENT 64 NOT SUPPORTED"); goto bad; //if(mp->magic != 0xFEEDFACF) { // werrstr("segment 32 in mach 64"); // goto bad; //} //seg = (MachSeg64*)c; //seg->vmaddr = swav(seg->vmaddr); //seg->vmsize = swav(seg->vmsize); //seg->fileoff = swav(seg->fileoff); //seg->filesize = swav(seg->filesize); //seg->maxprot = swal(seg->maxprot); //seg->initprot = swal(seg->initprot); //seg->nsects = swal(seg->nsects); //seg->flags = swal(seg->flags); //if (strcmp(seg->segname, "__TEXT") == 0) { // textva = seg->vmaddr; // textoff = seg->fileoff; // textsize = seg->vmsize; // sect = (MachSect64*)(cmdp + sizeof(MachSeg64)); // for(j = 0; j < seg->nsects; j++, sect++) { // if (strcmp(sect->sectname, "__gosymtab") == 0) { // symoff = swal(sect->offset); // symsize = swal(sect->size); // } // if (strcmp(sect->sectname, "__gopclntab") == 0) { // pclnoff = swal(sect->offset); // pclnsize = swal(sect->size); // } // } //} //if (strcmp(seg->segname, "__DATA") == 0) { // datava = seg->vmaddr; // dataoff = seg->fileoff; // datasize = seg->filesize; // bsssize = seg->vmsize - seg->filesize; //} break; case MACH_UNIXTHREAD: break; case MACH_SYMSEG: if (symtab == 0) { symtab = (MachSymSeg*)c; symoff = swal(symtab->fileoff); symsize = swal(symtab->filesize); } else if (pclntab == 0) { pclntab = (MachSymSeg*)c; pclnoff = swal(pclntab->fileoff); pclnsize = swal(pclntab->filesize); } break; } cmdp += c->size; } if (textva == 0 || datava == 0) { free(cmd); free(cmdbuf); return 0; } /* compute entry by taking address after header - weird - BUG? */ settext(fp, textva+sizeof(Machhdr) + mp->sizeofcmds, textva, textsize, textoff); setdata(fp, datava, datasize, dataoff, bsssize); if(symoff > 0) setsym(fp, symoff, symsize, 0, 0, pclnoff, pclnsize); free(cmd); free(cmdbuf); return 1; bad: free(cmd); free(cmdbuf); return 0; }
/* * Elf32 and Elf64 binaries. */ static int elf64dotout(int fd, Fhdr *fp, ExecHdr *hp) { uvlong (*swav)(uvlong); uint32 (*swal)(uint32); ushort (*swab)(ushort); Ehdr64 *ep; Phdr64 *ph; Shdr64 *sh; int i, it, id, is, phsz, shsz; /* bitswap the header according to the DATA format */ ep = &hp->e.elfhdr64; if(ep->ident[CLASS] != ELFCLASS64) { werrstr("bad ELF class - not 32 bit or 64 bit"); return 0; } if(ep->ident[DATA] == ELFDATA2LSB) { swab = leswab; swal = leswal; swav = leswav; } else if(ep->ident[DATA] == ELFDATA2MSB) { swab = beswab; swal = beswal; swav = beswav; } 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 = swav(ep->phoff); ep->shoff = swav(ep->shoff); ep->flags = swav(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 AMD64: mach = &mamd64; fp->type = FAMD64; break; default: return 0; } if(ep->phentsize != sizeof(Phdr64)) { werrstr("bad ELF header size"); return 0; } phsz = sizeof(Phdr64)*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(Shdr64)*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(ph); free(sh); 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(ph); free(sh); return 1; }