void cmdmap(Map *map) { int i; char name[MAXSYM]; extern char lastc; rdc(); readsym(name); i = findseg(map, name); if (i < 0) /* not found */ error("Invalid map name"); if (expr(0)) { if (strcmp(name, "text") == 0) textseg(expv, &fhdr); map->seg[i].b = expv; } else error("Invalid base address"); if (expr(0)) map->seg[i].e = expv; else error("Invalid end address"); if (expr(0)) map->seg[i].f = expv; else error("Invalid file offset"); if (rdc()=='?' && map == cormap) { if (fcor) close(fcor); fcor=fsym; corfil=symfil; cormap = symmap; } else if (lastc == '/' && map == symmap) { if (fsym) close(fsym); fsym=fcor; symfil=corfil; symmap=cormap; } else reread(); }
item(int a) { /* name [ . local ] | number | . | ^ | <register | 'x | | */ char *base; char savc; uvlong e; Symbol s; char gsym[MAXSYM], lsym[MAXSYM]; readchar(); if (isfileref()) { readfname(gsym); rdc(); /* skip white space */ if (lastc == ':') { /* it better be */ rdc(); /* skip white space */ if (!getnum(readchar)) error("bad number"); if (expv == 0) expv = 1; /* file begins at line 1 */ expv = file2pc(gsym, expv); if (expv == -1) error("%r"); return 1; } error("bad file location"); } else if (symchar(0)) { readsym(gsym); if (lastc=='.') { readchar(); /* ugh */ if (lastc == '.') { lsym[0] = '.'; readchar(); readsym(lsym+1); } else if (symchar(0)) { readsym(lsym); } else lsym[0] = 0; if (localaddr(cormap, gsym, lsym, &e, rget) < 0) error("%r"); expv = e; } else { if (lookup(0, gsym, &s) == 0) error("symbol not found"); expv = s.value; } reread(); } else if (getnum(readchar)) { ; } else if (lastc=='.') { readchar(); if (!symchar(0) && lastc != '.') { expv = dot; } else { if (findsym(rget(cormap, mach->pc), CTEXT, &s) == 0) error("no current function"); if (lastc == '.') { lsym[0] = '.'; readchar(); readsym(lsym+1); } else readsym(lsym); if (localaddr(cormap, s.name, lsym, &e, rget) < 0) error("%r"); expv = e; } reread(); } else if (lastc=='"') { expv=ditto; } else if (lastc=='+') { expv=inkdot(dotinc); } else if (lastc=='^') { expv=inkdot(-dotinc); } else if (lastc=='<') { savc=rdc(); base = regname(savc); expv = rget(cormap, base); } else if (lastc=='\'') expv = ascval(); else if (a) error("address expected"); else { reread(); return(0); } return(1); }
void ldpe(Biobuf *f, char *pkg, int64 len, char *pn) { char *name; int32 base; int i, j, l, numaux; PeObj *obj; PeSect *sect, *rsect; IMAGE_SECTION_HEADER sh; uchar symbuf[18]; Sym *s; Reloc *r, *rp; PeSym *sym; USED(len); USED(pkg); if(debug['v']) Bprint(&bso, "%5.2f ldpe %s\n", cputime(), pn); sect = nil; version++; base = Boffset(f); obj = mal(sizeof *obj); obj->f = f; obj->base = base; obj->name = pn; // read header if(Bread(f, &obj->fh, sizeof obj->fh) != sizeof obj->fh) goto bad; // load section list obj->sect = mal(obj->fh.NumberOfSections*sizeof obj->sect[0]); obj->nsect = obj->fh.NumberOfSections; for(i=0; i < obj->fh.NumberOfSections; i++) { if(Bread(f, &obj->sect[i].sh, sizeof sh) != sizeof sh) goto bad; obj->sect[i].size = obj->sect[i].sh.SizeOfRawData; obj->sect[i].name = (char*)obj->sect[i].sh.Name; // TODO return error if found .cormeta } // load string table Bseek(f, base+obj->fh.PointerToSymbolTable+18*obj->fh.NumberOfSymbols, 0); if(Bread(f, &l, sizeof l) != sizeof l) goto bad; obj->snames = mal(l); Bseek(f, base+obj->fh.PointerToSymbolTable+18*obj->fh.NumberOfSymbols, 0); if(Bread(f, obj->snames, l) != l) goto bad; // read symbols obj->pesym = mal(obj->fh.NumberOfSymbols*sizeof obj->pesym[0]); obj->npesym = obj->fh.NumberOfSymbols; Bseek(f, base+obj->fh.PointerToSymbolTable, 0); for(i=0; i<obj->fh.NumberOfSymbols; i+=numaux+1) { Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*i, 0); if(Bread(f, symbuf, sizeof symbuf) != sizeof symbuf) goto bad; if((symbuf[0] == 0) && (symbuf[1] == 0) && (symbuf[2] == 0) && (symbuf[3] == 0)) { l = le32(&symbuf[4]); obj->pesym[i].name = (char*)&obj->snames[l]; } else { // sym name length <= 8 obj->pesym[i].name = mal(9); strncpy(obj->pesym[i].name, (char*)symbuf, 8); obj->pesym[i].name[8] = 0; } obj->pesym[i].value = le32(&symbuf[8]); obj->pesym[i].sectnum = le16(&symbuf[12]); obj->pesym[i].sclass = symbuf[16]; obj->pesym[i].aux = symbuf[17]; obj->pesym[i].type = le16(&symbuf[14]); numaux = obj->pesym[i].aux; if (numaux < 0) numaux = 0; } // create symbols for mapped sections for(i=0; i<obj->nsect; i++) { sect = &obj->sect[i]; if(sect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE) continue; if(map(obj, sect) < 0) goto bad; name = smprint("%s(%s)", pn, sect->name); s = lookup(name, version); free(name); switch(sect->sh.Characteristics&(IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_CNT_INITIALIZED_DATA| IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE)) { case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ: //.rdata s->type = SRODATA; break; case IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.bss s->type = SBSS; break; case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.data s->type = SDATA; break; case IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ: //.text s->type = STEXT; break; default: werrstr("unexpected flags for PE section %s", sect->name); goto bad; } s->p = sect->base; s->np = sect->size; s->size = sect->size; if(s->type == STEXT) { if(etextp) etextp->next = s; else textp = s; etextp = s; } sect->sym = s; if(strcmp(sect->name, ".rsrc") == 0) setpersrc(sect->sym); } // load relocations for(i=0; i<obj->nsect; i++) { rsect = &obj->sect[i]; if(rsect->sym == 0 || rsect->sh.NumberOfRelocations == 0) continue; if(rsect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE) continue; r = mal(rsect->sh.NumberOfRelocations*sizeof r[0]); Bseek(f, obj->base+rsect->sh.PointerToRelocations, 0); for(j=0; j<rsect->sh.NumberOfRelocations; j++) { rp = &r[j]; if(Bread(f, symbuf, 10) != 10) goto bad; uint32 rva, symindex; uint16 type; rva = le32(&symbuf[0]); symindex = le32(&symbuf[4]); type = le16(&symbuf[8]); if(readsym(obj, symindex, &sym) < 0) goto bad; if(sym->sym == nil) { werrstr("reloc of invalid sym %s idx=%d type=%d", sym->name, symindex, sym->type); goto bad; } rp->sym = sym->sym; rp->siz = 4; rp->off = rva; switch(type) { default: diag("%s: unknown relocation type %d;", pn, type); case IMAGE_REL_I386_REL32: case IMAGE_REL_AMD64_REL32: case IMAGE_REL_AMD64_ADDR32: // R_X86_64_PC32 case IMAGE_REL_AMD64_ADDR32NB: rp->type = D_PCREL; rp->add = le32(rsect->base+rp->off); break; case IMAGE_REL_I386_DIR32NB: case IMAGE_REL_I386_DIR32: rp->type = D_ADDR; // load addend from image rp->add = le32(rsect->base+rp->off); break; case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64 rp->siz = 8; rp->type = D_ADDR; // load addend from image rp->add = le64(rsect->base+rp->off); break; } } qsort(r, rsect->sh.NumberOfRelocations, sizeof r[0], rbyoff); s = rsect->sym; s->r = r; s->nr = rsect->sh.NumberOfRelocations; } // enter sub-symbols into symbol table. for(i=0; i<obj->npesym; i++) { if(obj->pesym[i].name == 0) continue; if(obj->pesym[i].name[0] == '.') //skip section continue; if(obj->pesym[i].sectnum > 0) { sect = &obj->sect[obj->pesym[i].sectnum-1]; if(sect->sym == 0) continue; } if(readsym(obj, i, &sym) < 0) goto bad; s = sym->sym; if(sym->sectnum == 0) {// extern if(s->type == SDYNIMPORT) s->plt = -2; // flag for dynimport in PE object files. if (s->type == SXREF && sym->value > 0) {// global data s->type = SDATA; s->size = sym->value; } continue; } else if (sym->sectnum > 0) { sect = &obj->sect[sym->sectnum-1]; if(sect->sym == 0) diag("%s: %s sym == 0!", pn, s->name); } else { diag("%s: %s sectnum < 0!", pn, s->name); } if(sect == nil) return; s->sub = sect->sym->sub; sect->sym->sub = s; s->type = sect->sym->type | SSUB; s->value = sym->value; s->size = 4; s->outer = sect->sym; if(sect->sym->type == STEXT) { Prog *p; if(s->text != P) diag("%s: duplicate definition of %s", pn, s->name); // build a TEXT instruction with a unique pc // just to make the rest of the linker happy. p = prg(); p->as = ATEXT; p->from.type = D_EXTERN; p->from.sym = s; p->textflag = 7; p->to.type = D_CONST; p->link = nil; p->pc = pc++; s->text = p; etextp->next = s; etextp = s; } } return; bad: diag("%s: malformed pe file: %r", pn); }
void ldelf(Biobuf *f, char *pkg, int64 len, char *pn) { int32 base; uint64 add, info; char *name; int i, j, rela, is64, n, flag; uchar hdrbuf[64]; uchar *p; ElfHdrBytes *hdr; ElfObj *obj; ElfSect *sect, *rsect; ElfSym sym; Endian *e; Reloc *r, *rp; LSym *s; LSym **symbols; symbols = nil; if(debug['v']) Bprint(&bso, "%5.2f ldelf %s\n", cputime(), pn); ctxt->version++; base = Boffset(f); if(Bread(f, hdrbuf, sizeof hdrbuf) != sizeof hdrbuf) goto bad; hdr = (ElfHdrBytes*)hdrbuf; if(memcmp(hdr->ident, ElfMagic, 4) != 0) goto bad; switch(hdr->ident[5]) { case ElfDataLsb: e = ≤ break; case ElfDataMsb: e = &be; break; default: goto bad; } // read header obj = mal(sizeof *obj); obj->e = e; obj->f = f; obj->base = base; obj->len = len; obj->name = pn; is64 = 0; if(hdr->ident[4] == ElfClass64) { ElfHdrBytes64* hdr; is64 = 1; hdr = (ElfHdrBytes64*)hdrbuf; obj->type = e->e16(hdr->type); obj->machine = e->e16(hdr->machine); obj->version = e->e32(hdr->version); obj->phoff = e->e64(hdr->phoff); obj->shoff = e->e64(hdr->shoff); obj->flags = e->e32(hdr->flags); obj->ehsize = e->e16(hdr->ehsize); obj->phentsize = e->e16(hdr->phentsize); obj->phnum = e->e16(hdr->phnum); obj->shentsize = e->e16(hdr->shentsize); obj->shnum = e->e16(hdr->shnum); obj->shstrndx = e->e16(hdr->shstrndx); } else { obj->type = e->e16(hdr->type); obj->machine = e->e16(hdr->machine); obj->version = e->e32(hdr->version); obj->entry = e->e32(hdr->entry); obj->phoff = e->e32(hdr->phoff); obj->shoff = e->e32(hdr->shoff); obj->flags = e->e32(hdr->flags); obj->ehsize = e->e16(hdr->ehsize); obj->phentsize = e->e16(hdr->phentsize); obj->phnum = e->e16(hdr->phnum); obj->shentsize = e->e16(hdr->shentsize); obj->shnum = e->e16(hdr->shnum); obj->shstrndx = e->e16(hdr->shstrndx); } obj->is64 = is64; if(hdr->ident[6] != obj->version) goto bad; if(e->e16(hdr->type) != ElfTypeRelocatable) { diag("%s: elf but not elf relocatable object", pn); return; } switch(thechar) { default: diag("%s: elf %s unimplemented", pn, thestring); return; case '5': if(e != &le || obj->machine != ElfMachArm || hdr->ident[4] != ElfClass32) { diag("%s: elf object but not arm", pn); return; } break; case '6': if(e != &le || obj->machine != ElfMachAmd64 || hdr->ident[4] != ElfClass64) { diag("%s: elf object but not amd64", pn); return; } break; case '8': if(e != &le || obj->machine != ElfMach386 || hdr->ident[4] != ElfClass32) { diag("%s: elf object but not 386", pn); return; } break; case '9': if(obj->machine != ElfMachPower64 || hdr->ident[4] != ElfClass64) { diag("%s: elf object but not ppc64", pn); return; } break; } // load section list into memory. obj->sect = mal(obj->shnum*sizeof obj->sect[0]); obj->nsect = obj->shnum; for(i=0; i<obj->nsect; i++) { if(Bseek(f, base+obj->shoff+i*obj->shentsize, 0) < 0) goto bad; sect = &obj->sect[i]; if(is64) { ElfSectBytes64 b; werrstr("short read"); if(Bread(f, &b, sizeof b) != sizeof b) goto bad; sect->name = (char*)(uintptr)e->e32(b.name); sect->type = e->e32(b.type); sect->flags = e->e64(b.flags); sect->addr = e->e64(b.addr); sect->off = e->e64(b.off); sect->size = e->e64(b.size); sect->link = e->e32(b.link); sect->info = e->e32(b.info); sect->align = e->e64(b.align); sect->entsize = e->e64(b.entsize); } else { ElfSectBytes b; werrstr("short read"); if(Bread(f, &b, sizeof b) != sizeof b) goto bad; sect->name = (char*)(uintptr)e->e32(b.name); sect->type = e->e32(b.type); sect->flags = e->e32(b.flags); sect->addr = e->e32(b.addr); sect->off = e->e32(b.off); sect->size = e->e32(b.size); sect->link = e->e32(b.link); sect->info = e->e32(b.info); sect->align = e->e32(b.align); sect->entsize = e->e32(b.entsize); } } // read section string table and translate names if(obj->shstrndx >= obj->nsect) { werrstr("shstrndx out of range %d >= %d", obj->shstrndx, obj->nsect); goto bad; } sect = &obj->sect[obj->shstrndx]; if(map(obj, sect) < 0) goto bad; for(i=0; i<obj->nsect; i++) if(obj->sect[i].name != nil) obj->sect[i].name = (char*)sect->base + (uintptr)obj->sect[i].name; // load string table for symbols into memory. obj->symtab = section(obj, ".symtab"); if(obj->symtab == nil) { // our work is done here - no symbols means nothing can refer to this file return; } if(obj->symtab->link <= 0 || obj->symtab->link >= obj->nsect) { diag("%s: elf object has symbol table with invalid string table link", pn); return; } obj->symstr = &obj->sect[obj->symtab->link]; if(is64) obj->nsymtab = obj->symtab->size / sizeof(ElfSymBytes64); else obj->nsymtab = obj->symtab->size / sizeof(ElfSymBytes); if(map(obj, obj->symtab) < 0) goto bad; if(map(obj, obj->symstr) < 0) goto bad; // load text and data segments into memory. // they are not as small as the section lists, but we'll need // the memory anyway for the symbol images, so we might // as well use one large chunk. // create symbols for mapped sections for(i=0; i<obj->nsect; i++) { sect = &obj->sect[i]; if((sect->type != ElfSectProgbits && sect->type != ElfSectNobits) || !(sect->flags&ElfSectFlagAlloc)) continue; if(sect->type != ElfSectNobits && map(obj, sect) < 0) goto bad; name = smprint("%s(%s)", pkg, sect->name); s = linklookup(ctxt, name, ctxt->version); free(name); switch((int)sect->flags&(ElfSectFlagAlloc|ElfSectFlagWrite|ElfSectFlagExec)) { default: werrstr("unexpected flags for ELF section %s", sect->name); goto bad; case ElfSectFlagAlloc: s->type = SRODATA; break; case ElfSectFlagAlloc + ElfSectFlagWrite: if(sect->type == ElfSectNobits) s->type = SNOPTRBSS; else s->type = SNOPTRDATA; break; case ElfSectFlagAlloc + ElfSectFlagExec: s->type = STEXT; break; } if(strcmp(sect->name, ".got") == 0 || strcmp(sect->name, ".toc") == 0) s->type = SELFGOT; if(sect->type == ElfSectProgbits) { s->p = sect->base; s->np = sect->size; } s->size = sect->size; s->align = sect->align; sect->sym = s; } // enter sub-symbols into symbol table. // symbol 0 is the null symbol. symbols = malloc(obj->nsymtab * sizeof(symbols[0])); if(symbols == nil) { diag("out of memory"); errorexit(); } for(i=1; i<obj->nsymtab; i++) { if(readsym(obj, i, &sym, 1) < 0) goto bad; symbols[i] = sym.sym; if(sym.type != ElfSymTypeFunc && sym.type != ElfSymTypeObject && sym.type != ElfSymTypeNone) continue; if(sym.shndx == ElfSymShnCommon) { s = sym.sym; if(s->size < sym.size) s->size = sym.size; if(s->type == 0 || s->type == SXREF) s->type = SNOPTRBSS; continue; } if(sym.shndx >= obj->nsect || sym.shndx == 0) continue; // even when we pass needSym == 1 to readsym, it might still return nil to skip some unwanted symbols if(sym.sym == S) continue; sect = obj->sect+sym.shndx; if(sect->sym == nil) { if(strncmp(sym.name, ".Linfo_string", 13) == 0) // clang does this continue; diag("%s: sym#%d: ignoring %s in section %d (type %d)", pn, i, sym.name, sym.shndx, sym.type); continue; } s = sym.sym; if(s->outer != S) { if(s->dupok) continue; diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s->name, s->outer->name, sect->sym->name); errorexit(); } s->sub = sect->sym->sub; sect->sym->sub = s; s->type = sect->sym->type | (s->type&~SMASK) | SSUB; if(!(s->cgoexport & CgoExportDynamic)) s->dynimplib = nil; // satisfy dynimport s->value = sym.value; s->size = sym.size; s->outer = sect->sym; if(sect->sym->type == STEXT) { if(s->external && !s->dupok) diag("%s: duplicate definition of %s", pn, s->name); s->external = 1; } if(obj->machine == ElfMachPower64) { flag = sym.other >> 5; if(2 <= flag && flag <= 6) s->localentry = 1 << (flag - 2); else if(flag == 7) diag("%s: invalid sym.other 0x%x for %s", pn, sym.other, s->name); } }
void ldelf(Biobuf *f, char *pkg, int64 len, char *pn) { int32 base; uint64 add, info; char *name; int i, j, rela, is64, n; uchar hdrbuf[64]; uchar *p; ElfHdrBytes *hdr; ElfObj *obj; ElfSect *sect, *rsect; ElfSym sym; Endian *e; Reloc *r, *rp; LSym *s; LSym **symbols; symbols = nil; if(debug['v']) Bprint(&bso, "%5.2f ldelf %s\n", cputime(), pn); ctxt->version++; base = Boffset(f); if(Bread(f, hdrbuf, sizeof hdrbuf) != sizeof hdrbuf) goto bad; hdr = (ElfHdrBytes*)hdrbuf; if(memcmp(hdr->ident, ElfMagic, 4) != 0) goto bad; switch(hdr->ident[5]) { case ElfDataLsb: e = ≤ break; case ElfDataMsb: e = &be; break; default: goto bad; } // read header obj = mal(sizeof *obj); obj->e = e; obj->f = f; obj->base = base; obj->len = len; obj->name = pn; is64 = 0; if(hdr->ident[4] == ElfClass64) { ElfHdrBytes64* hdr; is64 = 1; hdr = (ElfHdrBytes64*)hdrbuf; obj->type = e->e16(hdr->type); obj->machine = e->e16(hdr->machine); obj->version = e->e32(hdr->version); obj->phoff = e->e64(hdr->phoff); obj->shoff = e->e64(hdr->shoff); obj->flags = e->e32(hdr->flags); obj->ehsize = e->e16(hdr->ehsize); obj->phentsize = e->e16(hdr->phentsize); obj->phnum = e->e16(hdr->phnum); obj->shentsize = e->e16(hdr->shentsize); obj->shnum = e->e16(hdr->shnum); obj->shstrndx = e->e16(hdr->shstrndx); } else { obj->type = e->e16(hdr->type); obj->machine = e->e16(hdr->machine); obj->version = e->e32(hdr->version); obj->entry = e->e32(hdr->entry); obj->phoff = e->e32(hdr->phoff); obj->shoff = e->e32(hdr->shoff); obj->flags = e->e32(hdr->flags); obj->ehsize = e->e16(hdr->ehsize); obj->phentsize = e->e16(hdr->phentsize); obj->phnum = e->e16(hdr->phnum); obj->shentsize = e->e16(hdr->shentsize); obj->shnum = e->e16(hdr->shnum); obj->shstrndx = e->e16(hdr->shstrndx); } obj->is64 = is64; if(hdr->ident[6] != obj->version) goto bad; if(e->e16(hdr->type) != ElfTypeRelocatable) { diag("%s: elf but not elf relocatable object", pn); return; } switch(thechar) { default: diag("%s: elf %s unimplemented", pn, thestring); return; case '5': if(e != &le || obj->machine != ElfMachArm || hdr->ident[4] != ElfClass32) { diag("%s: elf object but not arm", pn); return; } break; case '6': if(e != &le || obj->machine != ElfMachAmd64 || hdr->ident[4] != ElfClass64) { diag("%s: elf object but not amd64", pn); return; } break; case '8': if(e != &le || obj->machine != ElfMach386 || hdr->ident[4] != ElfClass32) { diag("%s: elf object but not 386", pn); return; } break; } // load section list into memory. obj->sect = mal(obj->shnum*sizeof obj->sect[0]); obj->nsect = obj->shnum; for(i=0; i<obj->nsect; i++) { if(Bseek(f, base+obj->shoff+i*obj->shentsize, 0) < 0) goto bad; sect = &obj->sect[i]; if(is64) { ElfSectBytes64 b; werrstr("short read"); if(Bread(f, &b, sizeof b) != sizeof b) goto bad; sect->name = (char*)(uintptr)e->e32(b.name); sect->type = e->e32(b.type); sect->flags = e->e64(b.flags); sect->addr = e->e64(b.addr); sect->off = e->e64(b.off); sect->size = e->e64(b.size); sect->link = e->e32(b.link); sect->info = e->e32(b.info); sect->align = e->e64(b.align); sect->entsize = e->e64(b.entsize); } else { ElfSectBytes b; werrstr("short read"); if(Bread(f, &b, sizeof b) != sizeof b) goto bad; sect->name = (char*)(uintptr)e->e32(b.name); sect->type = e->e32(b.type); sect->flags = e->e32(b.flags); sect->addr = e->e32(b.addr); sect->off = e->e32(b.off); sect->size = e->e32(b.size); sect->link = e->e32(b.link); sect->info = e->e32(b.info); sect->align = e->e32(b.align); sect->entsize = e->e32(b.entsize); } } // read section string table and translate names if(obj->shstrndx >= obj->nsect) { werrstr("shstrndx out of range %d >= %d", obj->shstrndx, obj->nsect); goto bad; } sect = &obj->sect[obj->shstrndx]; if(map(obj, sect) < 0) goto bad; for(i=0; i<obj->nsect; i++) if(obj->sect[i].name != nil) obj->sect[i].name = (char*)sect->base + (uintptr)obj->sect[i].name; // load string table for symbols into memory. obj->symtab = section(obj, ".symtab"); if(obj->symtab == nil) { // our work is done here - no symbols means nothing can refer to this file return; } if(obj->symtab->link <= 0 || obj->symtab->link >= obj->nsect) { diag("%s: elf object has symbol table with invalid string table link", pn); return; } obj->symstr = &obj->sect[obj->symtab->link]; if(is64) obj->nsymtab = obj->symtab->size / sizeof(ElfSymBytes64); else obj->nsymtab = obj->symtab->size / sizeof(ElfSymBytes); if(map(obj, obj->symtab) < 0) goto bad; if(map(obj, obj->symstr) < 0) goto bad; // load text and data segments into memory. // they are not as small as the section lists, but we'll need // the memory anyway for the symbol images, so we might // as well use one large chunk. // create symbols for mapped sections for(i=0; i<obj->nsect; i++) { sect = &obj->sect[i]; if((sect->type != ElfSectProgbits && sect->type != ElfSectNobits) || !(sect->flags&ElfSectFlagAlloc)) continue; if(sect->type != ElfSectNobits && map(obj, sect) < 0) goto bad; name = smprint("%s(%s)", pkg, sect->name); s = linklookup(ctxt, name, ctxt->version); free(name); switch((int)sect->flags&(ElfSectFlagAlloc|ElfSectFlagWrite|ElfSectFlagExec)) { default: werrstr("unexpected flags for ELF section %s", sect->name); goto bad; case ElfSectFlagAlloc: s->type = SRODATA; break; case ElfSectFlagAlloc + ElfSectFlagWrite: s->type = SNOPTRDATA; break; case ElfSectFlagAlloc + ElfSectFlagExec: s->type = STEXT; break; } if(sect->type == ElfSectProgbits) { s->p = sect->base; s->np = sect->size; } s->size = sect->size; s->align = sect->align; sect->sym = s; } // enter sub-symbols into symbol table. // symbol 0 is the null symbol. symbols = malloc(obj->nsymtab * sizeof(symbols[0])); if(symbols == nil) { diag("out of memory"); errorexit(); } for(i=1; i<obj->nsymtab; i++) { if(readsym(obj, i, &sym, 1) < 0) goto bad; symbols[i] = sym.sym; if(sym.type != ElfSymTypeFunc && sym.type != ElfSymTypeObject && sym.type != ElfSymTypeNone) continue; if(sym.shndx == ElfSymShnCommon) { s = sym.sym; if(s->size < sym.size) s->size = sym.size; if(s->type == 0 || s->type == SXREF) s->type = SNOPTRBSS; continue; } if(sym.shndx >= obj->nsect || sym.shndx == 0) continue; // even when we pass needSym == 1 to readsym, it might still return nil to skip some unwanted symbols if(sym.sym == S) continue; sect = obj->sect+sym.shndx; if(sect->sym == nil) { if(strncmp(sym.name, ".Linfo_string", 13) == 0) // clang does this continue; diag("%s: sym#%d: ignoring %s in section %d (type %d)", pn, i, sym.name, sym.shndx, sym.type); continue; } s = sym.sym; if(s->outer != S) { if(s->dupok) continue; diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s->name, s->outer->name, sect->sym->name); errorexit(); } s->sub = sect->sym->sub; sect->sym->sub = s; s->type = sect->sym->type | (s->type&~SMASK) | SSUB; if(!(s->cgoexport & CgoExportDynamic)) s->dynimplib = nil; // satisfy dynimport s->value = sym.value; s->size = sym.size; s->outer = sect->sym; if(sect->sym->type == STEXT) { if(s->external && !s->dupok) diag("%s: duplicate definition of %s", pn, s->name); s->external = 1; } } // Sort outer lists by address, adding to textp. // This keeps textp in increasing address order. for(i=0; i<obj->nsect; i++) { s = obj->sect[i].sym; if(s == S) continue; if(s->sub) s->sub = listsort(s->sub, valuecmp, offsetof(LSym, sub)); if(s->type == STEXT) { if(s->onlist) sysfatal("symbol %s listed multiple times", s->name); s->onlist = 1; if(ctxt->etextp) ctxt->etextp->next = s; else ctxt->textp = s; ctxt->etextp = s; for(s = s->sub; s != S; s = s->sub) { if(s->onlist) sysfatal("symbol %s listed multiple times", s->name); s->onlist = 1; ctxt->etextp->next = s; ctxt->etextp = s; } } } // load relocations for(i=0; i<obj->nsect; i++) { rsect = &obj->sect[i]; if(rsect->type != ElfSectRela && rsect->type != ElfSectRel) continue; if(rsect->info >= obj->nsect || obj->sect[rsect->info].base == nil) continue; sect = &obj->sect[rsect->info]; if(map(obj, rsect) < 0) goto bad; rela = rsect->type == ElfSectRela; n = rsect->size/(4+4*is64)/(2+rela); r = mal(n*sizeof r[0]); p = rsect->base; for(j=0; j<n; j++) { add = 0; rp = &r[j]; if(is64) { // 64-bit rel/rela rp->off = e->e64(p); p += 8; info = e->e64(p); p += 8; if(rela) { add = e->e64(p); p += 8; } } else { // 32-bit rel/rela rp->off = e->e32(p); p += 4; info = e->e32(p); info = info>>8<<32 | (info&0xff); // convert to 64-bit info p += 4; if(rela) { add = e->e32(p); p += 4; } } if((info & 0xffffffff) == 0) { // skip R_*_NONE relocation j--; n--; continue; } if((info >> 32) == 0) { // absolute relocation, don't bother reading the null symbol rp->sym = S; } else { if(readsym(obj, info>>32, &sym, 0) < 0) goto bad; sym.sym = symbols[info>>32]; if(sym.sym == nil) { werrstr("%s#%d: reloc of invalid sym #%d %s shndx=%d type=%d", sect->sym->name, j, (int)(info>>32), sym.name, sym.shndx, sym.type); goto bad; } rp->sym = sym.sym; } rp->type = reltype(pn, (uint32)info, &rp->siz); if(rela) rp->add = add; else { // load addend from image if(rp->siz == 4) rp->add = e->e32(sect->base+rp->off); else if(rp->siz == 8) rp->add = e->e64(sect->base+rp->off); else diag("invalid rela size %d", rp->siz); } if(rp->siz == 4) rp->add = (int32)rp->add; //print("rel %s %d %d %s %#llx\n", sect->sym->name, rp->type, rp->siz, rp->sym->name, rp->add); }
void ldpe(Biobuf *f, char *pkg, int64 len, char *pn) { char *name; int32 base; uint32 l; int i, j, numaux; PeObj *obj; PeSect *sect, *rsect; IMAGE_SECTION_HEADER sh; uchar symbuf[18]; LSym *s; Reloc *r, *rp; PeSym *sym; USED(len); if(debug['v']) Bprint(&bso, "%5.2f ldpe %s\n", cputime(), pn); sect = nil; ctxt->version++; base = Boffset(f); obj = mal(sizeof *obj); obj->f = f; obj->base = base; obj->name = pn; // read header if(Bread(f, &obj->fh, sizeof obj->fh) != sizeof obj->fh) goto bad; // load section list obj->sect = mal(obj->fh.NumberOfSections*sizeof obj->sect[0]); obj->nsect = obj->fh.NumberOfSections; for(i=0; i < obj->fh.NumberOfSections; i++) { if(Bread(f, &obj->sect[i].sh, sizeof sh) != sizeof sh) goto bad; obj->sect[i].size = obj->sect[i].sh.SizeOfRawData; obj->sect[i].name = (char*)obj->sect[i].sh.Name; // TODO return error if found .cormeta } // load string table Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*obj->fh.NumberOfSymbols, 0); if(Bread(f, symbuf, 4) != 4) goto bad; l = le32(symbuf); obj->snames = mal(l); Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*obj->fh.NumberOfSymbols, 0); if(Bread(f, obj->snames, l) != l) goto bad; // read symbols obj->pesym = mal(obj->fh.NumberOfSymbols*sizeof obj->pesym[0]); obj->npesym = obj->fh.NumberOfSymbols; Bseek(f, base+obj->fh.PointerToSymbolTable, 0); for(i=0; i<obj->fh.NumberOfSymbols; i+=numaux+1) { Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*i, 0); if(Bread(f, symbuf, sizeof symbuf) != sizeof symbuf) goto bad; if((symbuf[0] == 0) && (symbuf[1] == 0) && (symbuf[2] == 0) && (symbuf[3] == 0)) { l = le32(&symbuf[4]); obj->pesym[i].name = (char*)&obj->snames[l]; } else { // sym name length <= 8 obj->pesym[i].name = mal(9); strncpy(obj->pesym[i].name, (char*)symbuf, 8); obj->pesym[i].name[8] = 0; } obj->pesym[i].value = le32(&symbuf[8]); obj->pesym[i].sectnum = le16(&symbuf[12]); obj->pesym[i].sclass = symbuf[16]; obj->pesym[i].aux = symbuf[17]; obj->pesym[i].type = le16(&symbuf[14]); numaux = obj->pesym[i].aux; if (numaux < 0) numaux = 0; } // create symbols for mapped sections for(i=0; i<obj->nsect; i++) { sect = &obj->sect[i]; if(sect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE) continue; if((sect->sh.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA)) == 0) { // This has been seen for .idata sections, which we // want to ignore. See issues 5106 and 5273. continue; } if(map(obj, sect) < 0) goto bad; name = smprint("%s(%s)", pkg, sect->name); s = linklookup(ctxt, name, ctxt->version); free(name); switch(sect->sh.Characteristics&(IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_CNT_INITIALIZED_DATA| IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE)) { case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ: //.rdata s->type = SRODATA; break; case IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.bss s->type = SBSS; break; case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.data s->type = SDATA; break; case IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ: //.text s->type = STEXT; break; default: werrstr("unexpected flags %#08ux for PE section %s", sect->sh.Characteristics, sect->name); goto bad; } s->p = sect->base; s->np = sect->size; s->size = sect->size; sect->sym = s; if(strcmp(sect->name, ".rsrc") == 0) setpersrc(sect->sym); } // load relocations for(i=0; i<obj->nsect; i++) { rsect = &obj->sect[i]; if(rsect->sym == 0 || rsect->sh.NumberOfRelocations == 0) continue; if(rsect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE) continue; if((sect->sh.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA)) == 0) { // This has been seen for .idata sections, which we // want to ignore. See issues 5106 and 5273. continue; } r = mal(rsect->sh.NumberOfRelocations*sizeof r[0]); Bseek(f, obj->base+rsect->sh.PointerToRelocations, 0); for(j=0; j<rsect->sh.NumberOfRelocations; j++) { rp = &r[j]; if(Bread(f, symbuf, 10) != 10) goto bad; uint32 rva, symindex; uint16 type; rva = le32(&symbuf[0]); symindex = le32(&symbuf[4]); type = le16(&symbuf[8]); if(readsym(obj, symindex, &sym) < 0) goto bad; if(sym->sym == nil) { werrstr("reloc of invalid sym %s idx=%d type=%d", sym->name, symindex, sym->type); goto bad; } rp->sym = sym->sym; rp->siz = 4; rp->off = rva; switch(type) { default: diag("%s: unknown relocation type %d;", pn, type); case IMAGE_REL_I386_REL32: case IMAGE_REL_AMD64_REL32: case IMAGE_REL_AMD64_ADDR32: // R_X86_64_PC32 case IMAGE_REL_AMD64_ADDR32NB: rp->type = R_PCREL; rp->add = (int32)le32(rsect->base+rp->off); break; case IMAGE_REL_I386_DIR32NB: case IMAGE_REL_I386_DIR32: rp->type = R_ADDR; // load addend from image rp->add = (int32)le32(rsect->base+rp->off); break; case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64 rp->siz = 8; rp->type = R_ADDR; // load addend from image rp->add = le64(rsect->base+rp->off); break; } // ld -r could generate multiple section symbols for the // same section but with different values, we have to take // that into account if (obj->pesym[symindex].name[0] == '.') rp->add += obj->pesym[symindex].value; } qsort(r, rsect->sh.NumberOfRelocations, sizeof r[0], rbyoff); s = rsect->sym; s->r = r; s->nr = rsect->sh.NumberOfRelocations; } // enter sub-symbols into symbol table. for(i=0; i<obj->npesym; i++) { if(obj->pesym[i].name == 0) continue; if(obj->pesym[i].name[0] == '.') //skip section continue; if(obj->pesym[i].sectnum > 0) { sect = &obj->sect[obj->pesym[i].sectnum-1]; if(sect->sym == 0) continue; } if(readsym(obj, i, &sym) < 0) goto bad; s = sym->sym; if(sym->sectnum == 0) {// extern if(s->type == SDYNIMPORT) s->plt = -2; // flag for dynimport in PE object files. if (s->type == SXREF && sym->value > 0) {// global data s->type = SDATA; s->size = sym->value; } continue; } else if (sym->sectnum > 0) { sect = &obj->sect[sym->sectnum-1]; if(sect->sym == 0) diag("%s: %s sym == 0!", pn, s->name); } else { diag("%s: %s sectnum < 0!", pn, s->name); } if(sect == nil) return; if(s->outer != S) { if(s->dupok) continue; diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s->name, s->outer->name, sect->sym->name); errorexit(); } s->sub = sect->sym->sub; sect->sym->sub = s; s->type = sect->sym->type | SSUB; s->value = sym->value; s->size = 4; s->outer = sect->sym; if(sect->sym->type == STEXT) { if(s->external && !s->dupok) diag("%s: duplicate definition of %s", pn, s->name); s->external = 1; } } // Sort outer lists by address, adding to textp. // This keeps textp in increasing address order. for(i=0; i<obj->nsect; i++) { s = obj->sect[i].sym; if(s == S) continue; if(s->sub) s->sub = listsort(s->sub, valuecmp, offsetof(LSym, sub)); if(s->type == STEXT) { if(s->onlist) sysfatal("symbol %s listed multiple times", s->name); s->onlist = 1; if(ctxt->etextp) ctxt->etextp->next = s; else ctxt->textp = s; ctxt->etextp = s; for(s = s->sub; s != S; s = s->sub) { if(s->onlist) sysfatal("symbol %s listed multiple times", s->name); s->onlist = 1; ctxt->etextp->next = s; ctxt->etextp = s; } } } return; bad: diag("%s: malformed pe file: %r", pn); }