// Inferno utils/8l/asm.c // http://code.google.com/p/inferno-os/source/browse/utils/8l/asm.c // // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) // Portions Copyright © 1997-1999 Vita Nuova Limited // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) // Portions Copyright © 2004,2006 Bruce Ellis // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others // Portions Copyright © 2009 The Go Authors. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. #include "l.h" #include "../ld/lib.h" #include "../ld/elf.h" #include "../ld/macho.h" #define Dbufslop 100 char linuxdynld[] = "/lib/ld-linux.so.2"; char freebsddynld[] = "/usr/libexec/ld-elf.so.1"; uint32 symdatva = 0x99<<24; int32 entryvalue(void) { char *a; Sym *s; a = INITENTRY; if(*a >= '0' && *a <= '9') return atolwhex(a); s = lookup(a, 0); if(s->type == 0) return INITTEXT; switch(s->type) { case STEXT: break; case SDATA: if(dlm) return s->value+INITDAT; default: diag("entry not text: %s", s->name); } return s->value; } void wputl(ushort w) { cput(w); cput(w>>8); } void wput(ushort w) { cput(w>>8); cput(w); } void lput(int32 l) { cput(l>>24); cput(l>>16); cput(l>>8); cput(l); } void lputl(int32 l) { cput(l); cput(l>>8); cput(l>>16); cput(l>>24); } void vputl(uvlong l) { lputl(l >> 32); lputl(l); } void strnput(char *s, int n) { for(; *s && n > 0; s++) { cput(*s); n--; } while(n > 0) { cput(0); n--; } } vlong addstring(Sym *s, char *str) { int n, m; vlong r; Prog *p; if(s->type == 0) s->type = SDATA; s->reachable = 1; r = s->value; n = strlen(str)+1; while(n > 0) { m = n; if(m > sizeof(p->to.scon)) m = sizeof(p->to.scon); p = newdata(s, s->value, m, D_EXTERN); p->to.type = D_SCONST; memmove(p->to.scon, str, m); s->value += m; str += m; n -= m; } return r; } vlong adduintxx(Sym *s, uint64 v, int wid) { vlong r; Prog *p; if(s->type == 0) s->type = SDATA; s->reachable = 1; r = s->value; p = newdata(s, s->value, wid, D_EXTERN); s->value += wid; p->to.type = D_CONST; p->to.offset = v; return r; } vlong adduint8(Sym *s, uint8 v) { return adduintxx(s, v, 1); } vlong adduint16(Sym *s, uint16 v) { return adduintxx(s, v, 2); } vlong adduint32(Sym *s, uint32 v) { return adduintxx(s, v, 4); } vlong adduint64(Sym *s, uint64 v) { return adduintxx(s, v, 8); } vlong addaddr(Sym *s, Sym *t) { vlong r; Prog *p; enum { Ptrsize = 4 }; if(s->type == 0) s->type = SDATA; s->reachable = 1; r = s->value; p = newdata(s, s->value, Ptrsize, D_EXTERN); s->value += Ptrsize; p->to.type = D_ADDR; p->to.index = D_EXTERN; p->to.offset = 0; p->to.sym = t; return r; } vlong addsize(Sym *s, Sym *t) { vlong r; Prog *p; enum { Ptrsize = 4 }; if(s->type == 0) s->type = SDATA; s->reachable = 1; r = s->value; p = newdata(s, s->value, Ptrsize, D_EXTERN); s->value += Ptrsize; p->to.type = D_SIZE; p->to.index = D_EXTERN; p->to.offset = 0; p->to.sym = t; return r; } vlong datoff(vlong addr) { if(addr >= INITDAT) return addr - INITDAT + rnd(HEADR+textsize, INITRND); diag("datoff %#llx", addr); return 0; } enum { ElfStrEmpty, ElfStrInterp, ElfStrHash, ElfStrGot, ElfStrGotPlt, ElfStrDynamic, ElfStrDynsym, ElfStrDynstr, ElfStrRel, ElfStrText, ElfStrData, ElfStrBss, ElfStrGosymtab, ElfStrGopclntab, ElfStrShstrtab, NElfStr }; vlong elfstr[NElfStr]; static int needlib(char *name) { char *p; Sym *s; /* reuse hash code in symbol table */ p = smprint(".dynlib.%s", name); s = lookup(p, 0); if(s->type == 0) { s->type = 100; // avoid SDATA, etc. return 1; } return 0; } void doelf(void) { Sym *s, *shstrtab, *dynamic, *dynstr, *d; int h, nsym, t; if(HEADTYPE != 7 && HEADTYPE != 8 && HEADTYPE != 9) return; /* predefine strings we need for section headers */ shstrtab = lookup(".shstrtab", 0); shstrtab->reachable = 1; elfstr[ElfStrEmpty] = addstring(shstrtab, ""); elfstr[ElfStrText] = addstring(shstrtab, ".text"); elfstr[ElfStrData] = addstring(shstrtab, ".data"); elfstr[ElfStrBss] = addstring(shstrtab, ".bss"); if(!debug['s']) { elfstr[ElfStrGosymtab] = addstring(shstrtab, ".gosymtab"); elfstr[ElfStrGopclntab] = addstring(shstrtab, ".gopclntab"); } elfstr[ElfStrShstrtab] = addstring(shstrtab, ".shstrtab"); if(!debug['d']) { /* -d suppresses dynamic loader format */ elfstr[ElfStrInterp] = addstring(shstrtab, ".interp"); elfstr[ElfStrHash] = addstring(shstrtab, ".hash"); elfstr[ElfStrGot] = addstring(shstrtab, ".got"); elfstr[ElfStrGotPlt] = addstring(shstrtab, ".got.plt"); elfstr[ElfStrDynamic] = addstring(shstrtab, ".dynamic"); elfstr[ElfStrDynsym] = addstring(shstrtab, ".dynsym"); elfstr[ElfStrDynstr] = addstring(shstrtab, ".dynstr"); elfstr[ElfStrRel] = addstring(shstrtab, ".rel"); /* interpreter string */ s = lookup(".interp", 0); s->reachable = 1; s->type = SDATA; // TODO: rodata /* dynamic symbol table - first entry all zeros */ s = lookup(".dynsym", 0); s->type = SDATA; s->reachable = 1; s->value += ELF32SYMSIZE; /* dynamic string table */ s = lookup(".dynstr", 0); addstring(s, ""); dynstr = s; /* relocation table */ s = lookup(".rel", 0); s->reachable = 1; s->type = SDATA; /* global offset table */ s = lookup(".got", 0); s->reachable = 1; s->type = SDATA; /* got.plt - ??? */ s = lookup(".got.plt", 0); s->reachable = 1; s->type = SDATA; /* define dynamic elf table */ s = lookup(".dynamic", 0); dynamic = s; /* * relocation entries for dynld symbols */ nsym = 1; // sym 0 is reserved for(h=0; hlink) { if(!s->reachable || (s->type != SDATA && s->type != SBSS) || s->dynldname == nil) continue; d = lookup(".rel", 0); addaddr(d, s); adduint32(d, ELF32_R_INFO(nsym, R_386_32)); nsym++; d = lookup(".dynsym", 0); adduint32(d, addstring(lookup(".dynstr", 0), s->dynldname)); adduint32(d, 0); /* value */ adduint32(d, 0); /* size of object */ t = STB_GLOBAL << 4; t |= STT_OBJECT; // works for func too, empirically adduint8(d, t); adduint8(d, 0); /* reserved */ adduint16(d, SHN_UNDEF); /* section where symbol is defined */ if(needlib(s->dynldlib)) elfwritedynent(dynamic, DT_NEEDED, addstring(dynstr, s->dynldlib)); } } /* * hash table. * only entries that other objects need to find when * linking us need to be in the table. right now that is * no entries. * * freebsd insists on having chains enough for all * the local symbols, though. for now, we just lay * down a trivial hash table with 1 bucket and a long chain, * because no one is actually looking for our symbols. */ s = lookup(".hash", 0); s->type = SDATA; // TODO: rodata s->reachable = 1; adduint32(s, 1); // nbucket adduint32(s, nsym); // nchain adduint32(s, nsym-1); // bucket 0 adduint32(s, 0); // chain 0 for(h=1; h nsym-2 -> ... -> 2 -> 1 -> 0 adduint32(s, h-1); /* * .dynamic table */ s = dynamic; elfwritedynentsym(s, DT_HASH, lookup(".hash", 0)); elfwritedynentsym(s, DT_SYMTAB, lookup(".dynsym", 0)); elfwritedynent(s, DT_SYMENT, ELF32SYMSIZE); elfwritedynentsym(s, DT_STRTAB, lookup(".dynstr", 0)); elfwritedynentsymsize(s, DT_STRSZ, lookup(".dynstr", 0)); elfwritedynentsym(s, DT_REL, lookup(".rel", 0)); elfwritedynentsymsize(s, DT_RELSZ, lookup(".rel", 0)); elfwritedynent(s, DT_RELENT, ELF32RELSIZE); elfwritedynent(s, DT_NULL, 0); } } void shsym(Elf64_Shdr *sh, Sym *s) { sh->addr = symaddr(s); sh->off = datoff(sh->addr); sh->size = s->size; } void phsh(Elf64_Phdr *ph, Elf64_Shdr *sh) { ph->vaddr = sh->addr; ph->paddr = ph->vaddr; ph->off = sh->off; ph->filesz = sh->size; ph->memsz = sh->size; ph->align = sh->addralign; } void asmb(void) { Prog *p; int32 v, magic; int a, dynsym; uint32 va, fo, w, symo, startva, machlink; uchar *op1; ulong expectpc; ElfEhdr *eh; ElfPhdr *ph, *pph; ElfShdr *sh; if(debug['v']) Bprint(&bso, "%5.2f asmb\n", cputime()); Bflush(&bso); seek(cout, HEADR, 0); pc = INITTEXT; curp = firstp; for(p = firstp; p != P; p = p->link) { if(p->as == ATEXT) curtext = p; curp = p; if(HEADTYPE == 8) { // native client expectpc = p->pc; p->pc = pc; asmins(p); if(p->pc != expectpc) { Bflush(&bso); diag("phase error %lux sb %lux in %s", p->pc, expectpc, TNAME); } while(pc < p->pc) { cput(0x90); // nop pc++; } } if(p->pc != pc) { Bflush(&bso); if(!debug['a']) print("%P\n", curp); diag("phase error %lux sb %lux in %s", p->pc, pc, TNAME); pc = p->pc; } if(HEADTYPE != 8) { asmins(p); if(pc != p->pc) { Bflush(&bso); diag("asmins changed pc %lux sb %lux in %s", p->pc, pc, TNAME); } } if(cbc < sizeof(and)) cflush(); a = (andptr - and); if(debug['a']) { Bprint(&bso, pcstr, pc); for(op1 = and; op1 < andptr; op1++) Bprint(&bso, "%.2ux", *op1 & 0xff); Bprint(&bso, "\t%P\n", curp); } if(dlm) { if(p->as == ATEXT) reloca = nil; else if(reloca != nil) diag("reloc failure: %P", curp); } memmove(cbp, and, a); cbp += a; pc += a; cbc -= a; } if(HEADTYPE == 8) { while(pc < INITDAT) { cput(0xf4); // hlt pc++; } } cflush(); switch(HEADTYPE) { default: diag("unknown header type %d", HEADTYPE); case 0: seek(cout, rnd(HEADR+textsize, 8192), 0); break; case 1: textsize = rnd(HEADR+textsize, 4096)-HEADR; seek(cout, textsize+HEADR, 0); break; case 2: seek(cout, HEADR+textsize, 0); break; case 3: case 4: seek(cout, HEADR+rnd(textsize, INITRND), 0); break; case 6: v = HEADR+textsize; seek(cout, v, 0); v = rnd(v, 4096) - v; while(v > 0) { cput(0); v--; } cflush(); break; case 7: case 8: case 9: v = rnd(HEADR+textsize, INITRND); seek(cout, v, 0); break; } if(debug['v']) Bprint(&bso, "%5.2f datblk\n", cputime()); Bflush(&bso); if(dlm){ char buf[8]; write(cout, buf, INITDAT-textsize); textsize = INITDAT; } for(v = 0; v < datsize; v += sizeof(buf)-Dbufslop) { if(datsize-v > sizeof(buf)-Dbufslop) datblk(v, sizeof(buf)-Dbufslop); else datblk(v, datsize-v); } machlink = 0; if(HEADTYPE == 6) machlink = domacholink(); symsize = 0; spsize = 0; lcsize = 0; symo = 0; if(!debug['s']) { if(debug['v']) Bprint(&bso, "%5.2f sym\n", cputime()); Bflush(&bso); switch(HEADTYPE) { default: case 0: seek(cout, rnd(HEADR+textsize, 8192)+datsize, 0); break; case 1: seek(cout, rnd(HEADR+textsize, INITRND)+datsize, 0); break; case 2: seek(cout, HEADR+textsize+datsize, 0); break; case 3: case 4: debug['s'] = 1; symo = HEADR+textsize+datsize; break; case 6: symo = rnd(HEADR+textsize, INITRND)+rnd(datsize, INITRND)+machlink; break; case 7: case 8: case 9: symo = rnd(HEADR+textsize, INITRND)+datsize; symo = rnd(symo, INITRND); break; } seek(cout, symo+8, 0); if(!debug['s']) asmsym(); if(debug['v']) Bprint(&bso, "%5.2f sp\n", cputime()); Bflush(&bso); if(debug['v']) Bprint(&bso, "%5.2f pc\n", cputime()); Bflush(&bso); if(!debug['s']) asmlc(); if(dlm) asmdyn(); cflush(); seek(cout, symo, 0); lputl(symsize); lputl(lcsize); cflush(); } else if(dlm){ seek(cout, HEADR+textsize+datsize, 0); asmdyn(); cflush(); } if(debug['v']) Bprint(&bso, "%5.2f headr\n", cputime()); Bflush(&bso); seek(cout, 0L, 0); switch(HEADTYPE) { default: case 0: /* garbage */ lput(0x160L<<16); /* magic and sections */ lput(0L); /* time and date */ lput(rnd(HEADR+textsize, 4096)+datsize); lput(symsize); /* nsyms */ lput((0x38L<<16)|7L); /* size of optional hdr and flags */ lput((0413<<16)|0437L); /* magic and version */ lput(rnd(HEADR+textsize, 4096)); /* sizes */ lput(datsize); lput(bsssize); lput(entryvalue()); /* va of entry */ lput(INITTEXT-HEADR); /* va of base of text */ lput(INITDAT); /* va of base of data */ lput(INITDAT+datsize); /* va of base of bss */ lput(~0L); /* gp reg mask */ lput(0L); lput(0L); lput(0L); lput(0L); lput(~0L); /* gp value ?? */ break; lputl(0); /* x */ case 1: /* unix coff */ /* * file header */ lputl(0x0004014c); /* 4 sections, magic */ lputl(0); /* unix time stamp */ lputl(0); /* symbol table */ lputl(0); /* nsyms */ lputl(0x0003001c); /* flags, sizeof a.out header */ /* * a.out header */ lputl(0x10b); /* magic, version stamp */ lputl(rnd(textsize, INITRND)); /* text sizes */ lputl(datsize); /* data sizes */ lputl(bsssize); /* bss sizes */ lput(entryvalue()); /* va of entry */ lputl(INITTEXT); /* text start */ lputl(INITDAT); /* data start */ /* * text section header */ s8put(".text"); lputl(HEADR); /* pa */ lputl(HEADR); /* va */ lputl(textsize); /* text size */ lputl(HEADR); /* file offset */ lputl(0); /* relocation */ lputl(0); /* line numbers */ lputl(0); /* relocation, line numbers */ lputl(0x20); /* flags text only */ /* * data section header */ s8put(".data"); lputl(INITDAT); /* pa */ lputl(INITDAT); /* va */ lputl(datsize); /* data size */ lputl(HEADR+textsize); /* file offset */ lputl(0); /* relocation */ lputl(0); /* line numbers */ lputl(0); /* relocation, line numbers */ lputl(0x40); /* flags data only */ /* * bss section header */ s8put(".bss"); lputl(INITDAT+datsize); /* pa */ lputl(INITDAT+datsize); /* va */ lputl(bsssize); /* bss size */ lputl(0); /* file offset */ lputl(0); /* relocation */ lputl(0); /* line numbers */ lputl(0); /* relocation, line numbers */ lputl(0x80); /* flags bss only */ /* * comment section header */ s8put(".comment"); lputl(0); /* pa */ lputl(0); /* va */ lputl(symsize+lcsize); /* comment size */ lputl(HEADR+textsize+datsize); /* file offset */ lputl(HEADR+textsize+datsize); /* offset of syms */ lputl(HEADR+textsize+datsize+symsize);/* offset of line numbers */ lputl(0); /* relocation, line numbers */ lputl(0x200); /* flags comment only */ break; case 2: /* plan9 */ magic = 4*11*11+7; if(dlm) magic |= 0x80000000; lput(magic); /* magic */ lput(textsize); /* sizes */ lput(datsize); lput(bsssize); lput(symsize); /* nsyms */ lput(entryvalue()); /* va of entry */ lput(spsize); /* sp offsets */ lput(lcsize); /* line offsets */ break; case 3: /* MS-DOS .COM */ break; case 4: /* fake MS-DOS .EXE */ v = rnd(HEADR+textsize, INITRND)+datsize; wputl(0x5A4D); /* 'MZ' */ wputl(v % 512); /* bytes in last page */ wputl(rnd(v, 512)/512); /* total number of pages */ wputl(0x0000); /* number of reloc items */ v = rnd(HEADR-(INITTEXT & 0xFFFF), 16); wputl(v/16); /* size of header */ wputl(0x0000); /* minimum allocation */ wputl(0xFFFF); /* maximum allocation */ wputl(0x0000); /* initial ss value */ wputl(0x0100); /* initial sp value */ wputl(0x0000); /* complemented checksum */ v = entryvalue(); wputl(v); /* initial ip value (!) */ wputl(0x0000); /* initial cs value */ wputl(0x0000); wputl(0x0000); wputl(0x003E); /* reloc table offset */ wputl(0x0000); /* overlay number */ break; case 6: asmbmacho(symdatva, symo); break; case 7: case 8: case 9: /* elf 386 */ if(HEADTYPE == 8) debug['d'] = 1; eh = getElfEhdr(); fo = HEADR; startva = INITTEXT - HEADR; va = startva + fo; w = textsize; /* This null SHdr must appear before all others */ sh = newElfShdr(elfstr[ElfStrEmpty]); /* program header info - but not on native client */ pph = nil; if(HEADTYPE != 8) { pph = newElfPhdr(); pph->type = PT_PHDR; pph->flags = PF_R + PF_X; pph->off = eh->ehsize; pph->vaddr = INITTEXT - HEADR + pph->off; pph->paddr = INITTEXT - HEADR + pph->off; pph->align = INITRND; } if(!debug['d']) { /* interpreter */ sh = newElfShdr(elfstr[ElfStrInterp]); sh->type = SHT_PROGBITS; sh->flags = SHF_ALLOC; sh->addralign = 1; switch(HEADTYPE) { case 7: elfinterp(sh, startva, linuxdynld); break; case 9: elfinterp(sh, startva, freebsddynld); break; } ph = newElfPhdr(); ph->type = PT_INTERP; ph->flags = PF_R; phsh(ph, sh); } ph = newElfPhdr(); ph->type = PT_LOAD; ph->flags = PF_X+PF_R; ph->vaddr = va; ph->paddr = va; ph->off = fo; ph->filesz = w; ph->memsz = w; ph->align = INITRND; fo = rnd(fo+w, INITRND); va = rnd(va+w, INITRND); w = datsize; ph = newElfPhdr(); ph->type = PT_LOAD; ph->flags = PF_W+PF_R; ph->off = fo; ph->vaddr = va; ph->paddr = va; ph->filesz = w; ph->memsz = w+bsssize; ph->align = INITRND; if(!debug['s'] && HEADTYPE != 8) { ph = newElfPhdr(); ph->type = PT_LOAD; ph->flags = PF_W+PF_R; ph->off = symo; ph->vaddr = symdatva; ph->paddr = symdatva; ph->filesz = 8+symsize+lcsize; ph->memsz = 8+symsize+lcsize; ph->align = INITRND; } /* Dynamic linking sections */ if (!debug['d']) { /* -d suppresses dynamic loader format */ /* S headers for dynamic linking */ sh = newElfShdr(elfstr[ElfStrGot]); sh->type = SHT_PROGBITS; sh->flags = SHF_ALLOC+SHF_WRITE; sh->entsize = 4; sh->addralign = 4; shsym(sh, lookup(".got", 0)); sh = newElfShdr(elfstr[ElfStrGotPlt]); sh->type = SHT_PROGBITS; sh->flags = SHF_ALLOC+SHF_WRITE; sh->entsize = 4; sh->addralign = 4; shsym(sh, lookup(".got.plt", 0)); dynsym = eh->shnum; sh = newElfShdr(elfstr[ElfStrDynsym]); sh->type = SHT_DYNSYM; sh->flags = SHF_ALLOC; sh->entsize = ELF32SYMSIZE; sh->addralign = 4; sh->link = dynsym+1; // dynstr // sh->info = index of first non-local symbol (number of local symbols) shsym(sh, lookup(".dynsym", 0)); sh = newElfShdr(elfstr[ElfStrDynstr]); sh->type = SHT_STRTAB; sh->flags = SHF_ALLOC; sh->addralign = 1; shsym(sh, lookup(".dynstr", 0)); sh = newElfShdr(elfstr[ElfStrHash]); sh->type = SHT_HASH; sh->flags = SHF_ALLOC; sh->entsize = 4; sh->addralign = 4; sh->link = dynsym; shsym(sh, lookup(".hash", 0)); sh = newElfShdr(elfstr[ElfStrRel]); sh->type = SHT_REL; sh->flags = SHF_ALLOC; sh->entsize = ELF32RELSIZE; sh->addralign = 4; sh->link = dynsym; shsym(sh, lookup(".rel", 0)); /* sh and PT_DYNAMIC for .dynamic section */ sh = newElfShdr(elfstr[ElfStrDynamic]); sh->type = SHT_DYNAMIC; sh->flags = SHF_ALLOC+SHF_WRITE; sh->entsize = 8; sh->addralign = 4; sh->link = dynsym+1; // dynstr shsym(sh, lookup(".dynamic", 0)); ph = newElfPhdr(); ph->type = PT_DYNAMIC; ph->flags = PF_R + PF_W; phsh(ph, sh); /* * Thread-local storage segment (really just size). */ if(tlsoffset != 0) { ph = newElfPhdr(); ph->type = PT_TLS; ph->flags = PF_R; ph->memsz = -tlsoffset; ph->align = 4; } } ph = newElfPhdr(); ph->type = PT_GNU_STACK; ph->flags = PF_W+PF_R; ph->align = 4; fo = ELFRESERVE; va = startva + fo; w = textsize; sh = newElfShdr(elfstr[ElfStrText]); sh->type = SHT_PROGBITS; sh->flags = SHF_ALLOC+SHF_EXECINSTR; sh->addr = va; sh->off = fo; sh->size = w; sh->addralign = 4; fo = rnd(fo+w, INITRND); va = rnd(va+w, INITRND); w = datsize; sh = newElfShdr(elfstr[ElfStrData]); sh->type = SHT_PROGBITS; sh->flags = SHF_WRITE+SHF_ALLOC; sh->addr = va; sh->off = fo; sh->size = w; sh->addralign = 4; fo += w; va += w; w = bsssize; sh = newElfShdr(elfstr[ElfStrBss]); sh->type = SHT_NOBITS; sh->flags = SHF_WRITE+SHF_ALLOC; sh->addr = va; sh->off = fo; sh->size = w; sh->addralign = 4; if (!debug['s']) { fo = symo+8; w = symsize; sh = newElfShdr(elfstr[ElfStrGosymtab]); sh->type = SHT_PROGBITS; sh->off = fo; sh->size = w; sh->addralign = 1; fo += w; w = lcsize; sh = newElfShdr(elfstr[ElfStrGopclntab]); sh->type = SHT_PROGBITS; sh->off = fo; sh->size = w; sh->addralign = 1; } sh = newElfShstrtab(elfstr[ElfStrShstrtab]); sh->type = SHT_STRTAB; sh->addralign = 1; shsym(sh, lookup(".shstrtab", 0)); /* Main header */ eh->ident[EI_MAG0] = '\177'; eh->ident[EI_MAG1] = 'E'; eh->ident[EI_MAG2] = 'L'; eh->ident[EI_MAG3] = 'F'; eh->ident[EI_CLASS] = ELFCLASS32; eh->ident[EI_DATA] = ELFDATA2LSB; eh->ident[EI_VERSION] = EV_CURRENT; switch(HEADTYPE) { case 8: eh->ident[EI_OSABI] = ELFOSABI_NACL; eh->ident[EI_ABIVERSION] = 6; eh->flags = 0x200000; // aligned mod 32 break; case 9: eh->ident[EI_OSABI] = 9; break; } eh->type = ET_EXEC; eh->machine = EM_386; eh->version = EV_CURRENT; eh->entry = entryvalue(); if(pph != nil) { pph->filesz = eh->phnum * eh->phentsize; pph->memsz = pph->filesz; } seek(cout, 0, 0); a = 0; a += elfwritehdr(); a += elfwritephdrs(); a += elfwriteshdrs(); cflush(); if(a+elfwriteinterp() > ELFRESERVE) diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE); break; } cflush(); } void s8put(char *n) { char name[8]; int i; strncpy(name, n, sizeof(name)); for(i=0; ilink) { a = &p->from; l = a->sym->value + a->offset - s; if(l >= n) continue; c = a->scale; i = 0; if(l < 0) { if(l+c <= 0) continue; i = -l; l = 0; } curp = p; if(!a->sym->reachable) diag("unreachable symbol in datblk - %s", a->sym->name); if(a->sym->type == SMACHO) continue; if(p->as != AINIT && p->as != ADYNT) { for(j=l+(c-i)-1; j>=l; j--) if(buf.dbuf[j]) { print("%P\n", p); diag("multiple initialization"); break; } } switch(p->to.type) { case D_FCONST: switch(c) { default: case 4: fl = ieeedtof(&p->to.ieee); cast = (char*)&fl; for(; ito.ieee; for(; ito.scon[i]; l++; } break; default: fl = p->to.offset; if(p->to.type == D_SIZE) fl += p->to.sym->size; if(p->to.type == D_ADDR) { if(p->to.index != D_STATIC && p->to.index != D_EXTERN) diag("DADDR type%P", p); if(p->to.sym) { if(p->to.sym->type == SUNDEF) ckoff(p->to.sym, fl); fl += p->to.sym->value; if(p->to.sym->type != STEXT && p->to.sym->type != SUNDEF) fl += INITDAT; if(dlm) dynreloc(p->to.sym, l+s+INITDAT, 1); } } cast = (char*)&fl; switch(c) { default: diag("bad nuxi %d %d\n%P", c, i, curp); break; case 1: for(; ilink) { a = &p->from; l = a->sym->value + a->offset - s; if(l < 0 || l >= n) continue; c = a->scale; i = 0; switch(p->to.type) { case D_FCONST: switch(c) { default: case 4: fl = ieeedtof(&p->to.ieee); cast = (char*)&fl; Bprint(&bso, pcstr, l+s+INITDAT); for(j=0; jto.ieee; Bprint(&bso, pcstr, l+s+INITDAT); for(j=0; jto.scon[j] & 0xff); Bprint(&bso, "\t%P\n", curp); break; default: fl = p->to.offset; if(p->to.type == D_SIZE) fl += p->to.sym->size; if(p->to.type == D_ADDR) { if(p->to.index != D_STATIC && p->to.index != D_EXTERN) diag("DADDR type%P", p); if(p->to.sym) { if(p->to.sym->type == SUNDEF) ckoff(p->to.sym, fl); fl += p->to.sym->value; if(p->to.sym->type != STEXT && p->to.sym->type != SUNDEF) fl += INITDAT; if(dlm) dynreloc(p->to.sym, l+s+INITDAT, 1); } } cast = (char*)&fl; switch(c) { default: diag("bad nuxi %d %d\n%P", c, i, curp); break; case 1: Bprint(&bso, pcstr, l+s+INITDAT); for(j=0; j