--- /dev/null +++ /sys/src/cmd/ld/Nt.c @@ -0,0 +1,51 @@ +#include +#include + +/* + * We can't include l.h, because Windoze wants to use some names + * like FLOAT and ABC which we declare. Define what we need here. + */ +typedef unsigned char uchar; +typedef unsigned int uint; +typedef unsigned long ulong; + +#define Chunk (1*1024*1024) + +void* +mysbrk(ulong size) +{ + void *v; + static int chunk; + static uchar *brk; + + if(chunk < size) { + chunk = Chunk; + if(chunk < size) + chunk = Chunk + size; + brk = VirtualAlloc(NULL, chunk, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if(brk == 0) + return (void*)-1; + } + v = brk; + chunk -= size; + brk += size; + return v; +} + +double +cputime(void) +{ + return 0.0; +} + +int +fileexists(char *name) +{ + int fd; + + fd = open(name, OREAD); + if(fd < 0) + return 0; + close(fd); + return 1; +} --- /dev/null +++ /sys/src/cmd/ld/Plan9.c @@ -0,0 +1,16 @@ +#include "l.h" + +void* +mysbrk(ulong size) +{ + return sbrk(size); +} + +int +fileexists(char *s) +{ + uchar dirbuf[400]; + + /* it's fine if stat result doesn't fit in dirbuf, since even then the file exists */ + return stat(s, dirbuf, sizeof(dirbuf)) >= 0; +} --- /dev/null +++ /sys/src/cmd/ld/Posix.c @@ -0,0 +1,46 @@ +#include "l.h" +#include +#include +#include +#undef getwd +#include /* For sysconf() and _SC_CLK_TCK */ + +void* +mysbrk(usize size) +{ + return (void*)sbrk(size); +} + +double +cputime(void) +{ + + struct tms tmbuf; + double ret_val; + + /* + * times() only fails if &tmbuf is invalid. + */ + (void)times(&tmbuf); + /* + * Return the total time (in system clock ticks) + * spent in user code and system + * calls by both the calling process and its children. + */ + ret_val = (double)(tmbuf.tms_utime + tmbuf.tms_stime + + tmbuf.tms_cutime + tmbuf.tms_cstime); + /* + * Convert to seconds. + */ + ret_val *= sysconf(_SC_CLK_TCK); + return ret_val; + +} + +int +fileexists(char *name) +{ + struct stat sb; + + return stat(name, &sb) >= 0; +} --- /dev/null +++ /sys/src/cmd/ld/elf.c @@ -0,0 +1,266 @@ +/* + * emit 32- or 64-bit elf headers for any architecture. + * this is a component of ?l. + */ +#include "l.h" + +enum { + /* offsets into string table */ + Stitext = 1, + Stidata = 7, + Stistrtab = 13, +}; + +void +elfident(int bo, int class) +{ + strnput("\177ELF", 4); /* e_ident */ + cput(class); + cput(bo); /* byte order */ + cput(1); /* version = CURRENT */ + if(debug['k']){ /* boot/embedded/standalone */ + cput(255); + cput(0); + } + else{ + cput(0); /* osabi = SYSV */ + cput(0); /* abiversion = 3 */ + } + strnput("", 7); +} + +void +elfstrtab(void) +{ + /* string table */ + cput(0); + strnput(".text", 5); /* +1 */ + cput(0); + strnput(".data", 5); /* +7 */ + cput(0); + strnput(".strtab", 7); /* +13 */ + cput(0); + cput(0); +} + +void +elf32phdr(void (*putl)(long), ulong type, ulong off, ulong vaddr, ulong paddr, + ulong filesz, ulong memsz, ulong prots, ulong align) +{ + putl(type); + putl(off); + putl(vaddr); + putl(paddr); + putl(filesz); + putl(memsz); + putl(prots); + putl(align); +} + +void +elf32shdr(void (*putl)(long), ulong name, ulong type, ulong flags, ulong vaddr, + ulong off, ulong sectsz, ulong link, ulong addnl, ulong align, + ulong entsz) +{ + putl(name); + putl(type); + putl(flags); + putl(vaddr); + putl(off); + putl(sectsz); + putl(link); + putl(addnl); + putl(align); + putl(entsz); +} + +static void +elf32sectab(void (*putl)(long)) +{ + seek(cout, HEADR+textsize+datsize+symsize, 0); + elf32shdr(putl, Stitext, Progbits, Salloc|Sexec, INITTEXT, + HEADR, textsize, 0, 0, 0x10000, 0); + elf32shdr(putl, Stidata, Progbits, Salloc|Swrite, INITDAT, + HEADR+textsize, datsize, 0, 0, 0x10000, 0); + elf32shdr(putl, Stistrtab, Strtab, 1 << 5, 0, + HEADR+textsize+datsize+symsize+3*Shdr32sz, 14, 0, 0, 1, 0); + elfstrtab(); +} + +/* if addpsects > 0, putpsects must emit exactly that many psects. */ +void +elf32(int mach, int bo, int addpsects, void (*putpsects)(Putl)) +{ + ulong phydata; + void (*putw)(long), (*putl)(long); + + if(bo == ELFDATA2MSB){ + putw = wput; + putl = lput; + }else if(bo == ELFDATA2LSB){ + putw = wputl; + putl = lputl; + }else{ + print("elf32 byte order is mixed-endian\n"); + errorexit(); + return; + } + + elfident(bo, ELFCLASS32); + putw(EXEC); + putw(mach); + putl(1L); /* version = CURRENT */ + putl(entryvalue()); /* entry vaddr */ + putl(Ehdr32sz); /* offset to first phdr */ + if(debug['S']) + putl(HEADR+textsize+datsize+symsize); /* offset to first shdr */ + else + putl(0); + putl(0L); /* flags */ + putw(Ehdr32sz); + putw(Phdr32sz); + putw(3 + addpsects); /* # of Phdrs */ + putw(Shdr32sz); + if(debug['S']){ + putw(3); /* # of Shdrs */ + putw(2); /* Shdr table index */ + }else{ + putw(0); + putw(0); + } + + /* + * could include ELF headers in text -- 8l doesn't, + * but in theory it aids demand loading. + */ + elf32phdr(putl, PT_LOAD, HEADR, INITTEXT, INITTEXTP, + textsize, textsize, R|X, INITRND); /* text */ + /* + * we need INITDATP, but it has to be computed. + * assume distance between INITTEXT & INITTEXTP is also + * correct for INITDAT and INITDATP. + */ + phydata = INITDAT - (INITTEXT - INITTEXTP); + elf32phdr(putl, PT_LOAD, HEADR+textsize, INITDAT, phydata, + datsize, datsize+bsssize, R|W|X, INITRND); /* data */ + elf32phdr(putl, NOPTYPE, HEADR+textsize+datsize, 0, 0, + symsize, lcsize, R, 4); /* symbol table */ + if (addpsects > 0) + putpsects(putl); + cflush(); + + if(debug['S']) + elf32sectab(putl); +} + +/* + * elf64 + */ + +void +elf64phdr(void (*putl)(long), void (*putll)(vlong), ulong type, uvlong off, + uvlong vaddr, uvlong paddr, uvlong filesz, uvlong memsz, ulong prots, + uvlong align) +{ + putl(type); + putl(prots); + putll(off); + putll(vaddr); + putll(paddr); + putll(filesz); + putll(memsz); + putll(align); +} + +void +elf64shdr(void (*putl)(long), void (*putll)(vlong), ulong name, ulong type, + uvlong flags, uvlong vaddr, uvlong off, uvlong sectsz, ulong link, + ulong addnl, uvlong align, uvlong entsz) +{ + putl(name); + putl(type); + putll(flags); + putll(vaddr); + putll(off); + putll(sectsz); + putl(link); + putl(addnl); + putll(align); + putll(entsz); +} + +static void +elf64sectab(void (*putl)(long), void (*putll)(vlong)) +{ + seek(cout, HEADR+textsize+datsize+symsize, 0); + elf64shdr(putl, putll, Stitext, Progbits, Salloc|Sexec, INITTEXT, + HEADR, textsize, 0, 0, 0x10000, 0); + elf64shdr(putl, putll, Stidata, Progbits, Salloc|Swrite, INITDAT, + HEADR+textsize, datsize, 0, 0, 0x10000, 0); + elf64shdr(putl, putll, Stistrtab, Strtab, 1 << 5, 0, + HEADR+textsize+datsize+symsize+3*Shdr64sz, 14, 0, 0, 1, 0); + elfstrtab(); +} + +/* if addpsects > 0, putpsects must emit exactly that many psects. */ +void +elf64(int mach, int bo, int addpsects, void (*putpsects)(Putl)) +{ + uvlong phydata; + void (*putw)(long), (*putl)(long); + void (*putll)(vlong); + + if(bo == ELFDATA2MSB){ + putw = wput; + putl = lput; + putll = llput; + }else if(bo == ELFDATA2LSB){ + putw = wputl; + putl = lputl; + putll = llputl; + }else{ + print("elf64 byte order is mixed-endian\n"); + errorexit(); + return; + } + + elfident(bo, ELFCLASS64); + putw(EXEC); + putw(mach); + putl(1L); /* version = CURRENT */ + putll(entryvalue()); /* entry vaddr */ + putll(Ehdr64sz); /* offset to first phdr */ + if(debug['S']) + putll(HEADR+textsize+datsize+symsize); /* offset to 1st shdr */ + else + putll(0); + putl(0L); /* flags */ + putw(Ehdr64sz); + putw(Phdr64sz); + putw(3 + addpsects); /* # of Phdrs */ + putw(Shdr64sz); + if(debug['S']){ + putw(3); /* # of Shdrs */ + putw(2); /* Shdr table index */ + }else{ + putw(0); + putw(0); + } + + elf64phdr(putl, putll, PT_LOAD, HEADR, INITTEXT, INITTEXTP, + textsize, textsize, R|X, INITRND); /* text */ + /* + * see 32-bit ELF case for physical data address computation. + */ + phydata = INITDAT - (INITTEXT - INITTEXTP); + elf64phdr(putl, putll, PT_LOAD, HEADR+textsize, INITDAT, phydata, + datsize, datsize+bsssize, R|W, INITRND); /* data */ + elf64phdr(putl, putll, NOPTYPE, HEADR+textsize+datsize, 0, 0, + symsize, lcsize, R, 4); /* symbol table */ + if (addpsects > 0) + putpsects(putl); + cflush(); + + if(debug['S']) + elf64sectab(putl, putll); +} --- /dev/null +++ /sys/src/cmd/ld/elf.h @@ -0,0 +1,97 @@ +enum { + Ehdr32sz = 52, + Phdr32sz = 32, + Shdr32sz = 40, + + Ehdr64sz = 64, + Phdr64sz = 56, + Shdr64sz = 64, +}; + +/* from /sys/src/libmach/elf.h */ +enum { + /* Ehdr codes */ + MAG0 = 0, /* ident[] indexes */ + MAG1 = 1, + MAG2 = 2, + MAG3 = 3, + CLASS = 4, + DATA = 5, + VERSION = 6, + + ELFCLASSNONE = 0, /* ident[CLASS] */ + ELFCLASS32 = 1, + ELFCLASS64 = 2, + ELFCLASSNUM = 3, + + ELFDATANONE = 0, /* ident[DATA] */ + ELFDATA2LSB = 1, + ELFDATA2MSB = 2, + ELFDATANUM = 3, + + NOETYPE = 0, /* type */ + REL = 1, + EXEC = 2, + DYN = 3, + CORE = 4, + + NONE = 0, /* machine */ + M32 = 1, /* AT&T WE 32100 */ + SPARC = 2, /* Sun SPARC */ + I386 = 3, /* Intel 80386 */ + M68K = 4, /* Motorola 68000 */ + M88K = 5, /* Motorola 88000 */ + I486 = 6, /* Intel 80486 */ + I860 = 7, /* Intel i860 */ + MIPS = 8, /* Mips R2000 */ + S370 = 9, /* Amdhal */ + MIPSR4K = 10, /* Mips R4000 */ + SPARC64 = 18, /* Sun SPARC v9 */ + POWER = 20, /* PowerPC */ + POWER64 = 21, /* PowerPC64 */ + ARM = 40, /* ARM */ + AMD64 = 62, /* Amd64 */ + ARM64 = 183, /* ARM64 */ + + NO_VERSION = 0, /* version, ident[VERSION] */ + CURRENT = 1, + + /* Phdr Codes */ + NOPTYPE = 0, /* type */ + PT_LOAD = 1, + DYNAMIC = 2, + INTERP = 3, + NOTE = 4, + SHLIB = 5, + PHDR = 6, + + R = 0x4, /* flags */ + W = 0x2, + X = 0x1, + + /* Shdr Codes */ + Progbits = 1, /* section types */ + Strtab = 3, + Nobits = 8, + + Swrite = 1, /* section attributes (flags) */ + Salloc = 2, + Sexec = 4, +}; + +typedef void (*Putl)(long); + +void elf32(int mach, int bo, int addpsects, void (*putpsects)(Putl)); +void elf32phdr(void (*putl)(long), ulong type, ulong off, ulong vaddr, + ulong paddr, ulong filesz, ulong memsz, ulong prots, ulong align); +void elf32shdr(void (*putl)(long), ulong name, ulong type, ulong flags, + ulong vaddr, ulong off, ulong sectsz, ulong link, ulong addnl, + ulong align, ulong entsz); + +void elf64(int mach, int bo, int addpsects, void (*putpsects)(Putl)); +void elf64phdr(void (*putl)(long), void (*putll)(vlong), ulong type, + uvlong off, uvlong vaddr, uvlong paddr, uvlong filesz, uvlong memsz, + ulong prots, uvlong align); +void elf64shdr(void (*putl)(long), void (*putll)(vlong), ulong name, + ulong type, uvlong flags, uvlong vaddr, uvlong off, uvlong sectsz, + ulong link, ulong addnl, uvlong align, uvlong entsz); --- /dev/null +++ /sys/src/cmd/ld/falloc.c @@ -0,0 +1,48 @@ +#include "l.h" + +/* + * fake malloc + */ +void* +malloc(usize n) +{ + return halloc(n); +} + +void +free(void *p) +{ + USED(p); +} + +void* +calloc(usize m, usize n) +{ + void *p; + + n *= m; + p = malloc(n); + memset(p, 0, n); + return p; +} + +/* + * not used by compiler or loader, but Windows needs it + */ +void* +realloc(void *p, usize n) +{ + void *new; + + new = malloc(n); + if(new != nil && p != nil) + memmove(new, p, n); /* safe only when adjecent hunks have no gaps */ + return new; +} + +void +setmalloctag(void *v, ulong pc) +{ + USED(v); + USED(pc); +} --- /dev/null +++ /sys/src/cmd/ld/ld.h @@ -0,0 +1,156 @@ +#include +#include +#include +#include "../ld/elf.h" + +typedef vlong int64; + +/* + * basic types in all loaders + */ + +typedef struct Adr Adr; +typedef struct Auto Auto; +typedef struct Count Count; +typedef struct Ieee Ieee; +typedef struct Prog Prog; +typedef struct Sym Sym; + +#ifndef EXTERN +#define EXTERN extern +#endif + +#define LIBNAMELEN 300 + +#define P ((Prog*)0) +#define S ((Sym*)0) +#define TNAME (curtext&&curtext->from.sym?curtext->from.sym->name:noname) + +struct Auto +{ + Sym* asym; + Auto* link; + vlong aoffset; + short type; +}; + +struct Count +{ + long count; + long outof; +}; + +enum +{ + + STRINGSZ = 200, + NHASH = 10007, + NHUNK = 100000, + MAXIO = 8192, + MAXHIST = 20, /* limit of path elements for history symbols */ +}; + +#define SIGNINTERN (1729*325*1729) /* signature of internal functions such as _div */ + +EXTERN union +{ + struct + { + uchar obuf[MAXIO]; /* output buffer */ + uchar ibuf[MAXIO]; /* input buffer */ + } u; + char dbuf[1]; +} buf; + +#define cbuf u.obuf +#define xbuf u.ibuf + +EXTERN int cbc; +EXTERN uchar* cbp; +EXTERN int cout; +EXTERN char debug[128]; +EXTERN char fnuxi4[4]; +EXTERN char fnuxi8[8]; +EXTERN Sym* hash[NHASH]; +EXTERN Sym* histfrog[MAXHIST]; +EXTERN int histfrogp; +EXTERN int histgen; +EXTERN char* library[50]; +EXTERN char* libraryobj[50]; +EXTERN int libraryp; +EXTERN int xrefresolv; +EXTERN char inuxi1[1]; +EXTERN char inuxi2[2]; +EXTERN char inuxi4[4]; +EXTERN uchar inuxi8[8]; +EXTERN char* thestring; +EXTERN char thechar; + +EXTERN int doexp, dlm; +EXTERN int imports, nimports; +EXTERN int exports, nexports; +EXTERN char* EXPTAB; +EXTERN Prog undefp; + +#define UP (&undefp) + +int Sconv(Fmt*); +void addhist(long, int); +void addlib(char*); +void addlibpath(char*); +void addlibroot(void); +vlong atolwhex(char*); +Prog* brchain(Prog*); +Prog* brloop(Prog*); +void cflush(void); +void ckoff(Sym*, long); +void collapsefrog(Sym*); +void cput(int); +void diag(char*, ...); +void errorexit(void); +double cputime(void); +void dodata(void); +void export(void); +int fileexists(char*); +int find1(long, int); +char* findlib(char*); +char* findlib(char*); +void follow(void); +void gethunk(void); +long hunkspace(void); +uchar* readsome(int, uchar*, uchar*, uchar*, int); +void* halloc(usize); +void histtoauto(void); +double ieeedtod(Ieee*); +long ieeedtof(Ieee*); +void import(void); +int isobjfile(char*); +void loadlib(void); +Sym* lookup(char*, int); +void mkfwd(void); +void* mysbrk(ulong); +void nopstat(char*, Count*); +void objfile(char*); +void patch(void); +void prasm(Prog*); +Prog* prg(void); +void readundefs(char*, int); +uchar* readsome(int, uchar*, uchar*, uchar*, int); +void readundefs(char*, int); +vlong rnd(vlong, long); +void strnput(char*, int); +void undef(void); +void undefsym(Sym*); +void xdefine(char*, int, vlong); +void xfol(Prog*); +void zerosig(char*); + +#pragma varargck type "A" int +#pragma varargck type "A" uint +#pragma varargck type "C" int +#pragma varargck type "D" Adr* +#pragma varargck type "N" Adr* +#pragma varargck type "P" Prog* +#pragma varargck type "S" char* + +#pragma varargck argpos diag 1 --- /dev/null +++ /sys/src/cmd/ld/mkcname @@ -0,0 +1,17 @@ +ed - l.h <<'!' +v/^ C_/d +g/^ C_NCLASS/s//&,/ +g/[ ]*=.*,/s//,/ +v/,/p +,s/^ C_/ "/ +,s/,.*$/",/ +1i +char *cnames[] = +{ +. +,a +}; +. +w cnam.c +Q +! --- /dev/null +++ /sys/src/cmd/ld/mkfile @@ -0,0 +1,2 @@ +all clean install nuke:VQ: + # --- /dev/null +++ /sys/src/cmd/ld/mod.c @@ -0,0 +1,203 @@ +#include "l.h" + +void +readundefs(char *f, int t) +{ + int i, n; + Sym *s; + Biobuf *b; + char *l, buf[256], *fields[64]; + + if(f == nil) + return; + b = Bopen(f, OREAD); + if(b == nil){ + diag("could not open %s: %r", f); + errorexit(); + } + while((l = Brdline(b, '\n')) != nil){ + n = Blinelen(b); + if(n >= sizeof(buf)){ + diag("%s: line too long", f); + errorexit(); + } + memmove(buf, l, n); + buf[n-1] = '\0'; + n = getfields(buf, fields, nelem(fields), 1, " \t\r\n"); + if(n == nelem(fields)){ + diag("%s: bad format", f); + errorexit(); + } + for(i = 0; i < n; i++){ + s = lookup(fields[i], 0); + s->type = SXREF; + s->subtype = t; + if(t == SIMPORT) + nimports++; + else + nexports++; + } + } + Bterm(b); +} + +void +undefsym(Sym *s) +{ + int n; + + n = imports; + if(s->value != 0) + diag("value != 0 on SXREF"); + if(n >= 1<value = n<type = SUNDEF; + imports++; +} + +void +zerosig(char *sp) +{ + Sym *s; + + s = lookup(sp, 0); + s->sig = 0; +} + +void +import(void) +{ + int i; + Sym *s; + + for(i = 0; i < NHASH; i++) + for(s = hash[i]; s != S; s = s->link) + if(s->sig != 0 && s->type == SXREF && (nimports == 0 || s->subtype == SIMPORT)){ + undefsym(s); + Bprint(&bso, "IMPORT: %s sig=%lux v=%lld\n", s->name, s->sig, (vlong)s->value); + } +} + +void +ckoff(Sym *s, long v) +{ + if(v < 0 || v >= 1<name); +} + +static Prog* +newdata(Sym *s, int o, int w, int t) +{ + Prog *p; + + p = prg(); + p->link = datap; + datap = p; + p->as = ADATA; + p->reg = w; + p->from.type = D_OREG; + p->from.name = t; + p->from.sym = s; + p->from.offset = o; + p->to.type = D_CONST; + p->to.name = D_NONE; + return p; +} + +void +export(void) +{ + int i, j, n, off, nb, sv, ne; + Sym *s, *et, *str, **esyms; + Prog *p; + char buf[NSNAME], *t; + + n = 0; + for(i = 0; i < NHASH; i++) + for(s = hash[i]; s != S; s = s->link) + if(s->sig != 0 && s->type != SXREF && s->type != SUNDEF && (nexports == 0 || s->subtype == SEXPORT)) + n++; + esyms = malloc(n*sizeof(Sym*)); + ne = n; + n = 0; + for(i = 0; i < NHASH; i++) + for(s = hash[i]; s != S; s = s->link) + if(s->sig != 0 && s->type != SXREF && s->type != SUNDEF && (nexports == 0 || s->subtype == SEXPORT)) + esyms[n++] = s; + for(i = 0; i < ne-1; i++) + for(j = i+1; j < ne; j++) + if(strcmp(esyms[i]->name, esyms[j]->name) > 0){ + s = esyms[i]; + esyms[i] = esyms[j]; + esyms[j] = s; + } + + nb = 0; + off = 0; + et = lookup(EXPTAB, 0); + if(et->type != 0 && et->type != SXREF) + diag("%s already defined", EXPTAB); + et->type = SDATA; + str = lookup(".string", 0); + if(str->type == 0) + str->type = SDATA; + sv = str->value; + for(i = 0; i < ne; i++){ + s = esyms[i]; + Bprint(&bso, "EXPORT: %s sig=%lux t=%d\n", s->name, s->sig, s->type); + + /* signature */ + p = newdata(et, off, sizeof(long), D_EXTERN); + off += sizeof(long); + p->to.offset = s->sig; + + /* address */ + p = newdata(et, off, sizeof(long), D_EXTERN); + off += sizeof(long); + p->to.name = D_EXTERN; + p->to.sym = s; + + /* string */ + t = s->name; + n = strlen(t)+1; + for(;;){ + buf[nb++] = *t; + sv++; + if(nb >= NSNAME){ + p = newdata(str, sv-NSNAME, NSNAME, D_STATIC); + p->to.type = D_SCONST; + p->to.sval = malloc(NSNAME); + memmove(p->to.sval, buf, NSNAME); + nb = 0; + } + if(*t++ == 0) + break; + } + + /* name */ + p = newdata(et, off, sizeof(long), D_EXTERN); + off += sizeof(long); + p->to.name = D_STATIC; + p->to.sym = str; + p->to.offset = sv-n; + } + + if(nb > 0){ + p = newdata(str, sv-nb, nb, D_STATIC); + p->to.type = D_SCONST; + p->to.sval = malloc(NSNAME); + memmove(p->to.sval, buf, nb); + } + + for(i = 0; i < 3; i++){ + newdata(et, off, sizeof(long), D_EXTERN); + off += sizeof(long); + } + et->value = off; + if(sv == 0) + sv = 1; + str->value = sv; + exports = ne; + free(esyms); +} --- /dev/null +++ /sys/src/cmd/ld/pass.c @@ -0,0 +1,381 @@ +#include "l.h" + +void +dodata(void) +{ + int i, t; + Sym *s; + Prog *p; + long orig, v; + + if(debug['v']) + Bprint(&bso, "%5.2f dodata\n", cputime()); + Bflush(&bso); + for(p = datap; p != P; p = p->link) { + s = p->from.sym; + if(p->as == ADYNT || p->as == AINIT) + s->value = dtype; + if(s->type == SBSS) + s->type = SDATA; + if(s->type != SDATA) + diag("initialize non-data (%d): %s\n%P", + s->type, s->name, p); + v = p->from.offset + p->reg; + if(v > s->value) + diag("initialize bounds (%lld): %s\n%P", + (vlong)s->value, s->name, p); + } + + if(debug['t']) { + /* + * pull out string constants + */ + for(p = datap; p != P; p = p->link) { + s = p->from.sym; + if(p->to.type == D_SCONST) + s->type = SSTRING; + } + } + + /* + * pass 1 + * assign 'small' variables to data segment + * (rationale is that data segment is more easily + * addressed through offset on REGSB) + */ + orig = 0; + for(i=0; ilink) { + t = s->type; + if(t != SDATA && t != SBSS) + continue; + v = s->value; + if(v == 0) { + diag("%s: no size", s->name); + v = 1; + } + v = rnd(v, 4); + s->value = v; + if(v > MINSIZ) + continue; + if(v >= 16) + orig = rnd(orig, 16); + else if(v >= 8) + orig = rnd(orig, 8); + s->value = orig; + orig += v; + s->type = SDATA1; + } + + /* + * pass 2 + * assign large 'data' variables to data segment + */ + for(i=0; ilink) { + t = s->type; + if(t != SDATA) { + if(t == SDATA1) + s->type = SDATA; + continue; + } + v = s->value; + if(v >= 16) + orig = rnd(orig, 16); + else if(v >= 8) + orig = rnd(orig, 8); + s->value = orig; + orig += v; + } + + while(orig & 7) + orig++; + datsize = orig; + + /* + * pass 3 + * everything else to bss segment + */ + for(i=0; ilink) { + if(s->type != SBSS) + continue; + v = s->value; + if(v >= 16) + orig = rnd(orig, 16); + else if(v >= 8) + orig = rnd(orig, 8); + s->value = orig; + orig += v; + } + while(orig & 7) + orig++; + bsssize = orig-datsize; + + xdefine("setSB", SDATA, 0L); + xdefine("bdata", SDATA, 0L); + xdefine("edata", SDATA, datsize); + xdefine("end", SBSS, datsize+bsssize); + xdefine("etext", STEXT, 0L); +} + +Prog* +brchain(Prog *p) +{ + int i; + + for(i=0; i<20; i++) { + if(p == P || !isbranch(p->as)) + return p; + p = p->cond; + } + return P; +} + +void +follow(void) +{ + if(debug['v']) + Bprint(&bso, "%5.2f follow\n", cputime()); + Bflush(&bso); + + firstp = prg(); + lastp = firstp; + xfol(textp); + + firstp = firstp->link; + lastp->link = P; +} + +void +xfol(Prog *p) +{ + Prog *q, *r; + int a, i; + +loop: + if(p == P) + return; + a = p->as; + if(a == ATEXT) + curtext = p; + if(isbranch(a)) { + q = p->cond; + if(q != P) { + p->mark |= FOLL; + p = q; + if(!(p->mark & FOLL)) + goto loop; + } + } + if(p->mark & FOLL) { + for(i=0,q=p; i<4; i++,q=q->link) { + if(q == lastp) + break; + a = q->as; + if(a == ANOP) { + i--; + continue; + } + if(isbranch(a) || isreturn(a)) + goto copy; + if(q->cond == nil || (q->cond->mark&FOLL)) + continue; + if(a != ABEQ && a != ABNE) + continue; + copy: + for(;;) { + r = prg(); + *r = *p; + if(!(r->mark&FOLL)) + print("cant happen 1\n"); + r->mark |= FOLL; + if(p != q) { + p = p->link; + lastp->link = r; + lastp = r; + continue; + } + lastp->link = r; + lastp = r; + if(isbranch(a) || isreturn(a)) + return; + r->as = a == ABNE? ABEQ: ABNE; + r->cond = p->link; + r->link = p->cond; + if(!(r->link->mark&FOLL)) + xfol(r->link); + if(!(r->cond->mark&FOLL)) + print("cant happen 2\n"); + return; + } + } + a = branchop(); + q = prg(); + q->as = a; + q->line = p->line; + q->to.type = D_BRANCH; + q->to.offset = p->pc; + q->cond = p; + p = q; + } + p->mark |= FOLL; + lastp->link = p; + lastp = p; + if(isbranch(a) || isreturn(a)) + return; + if(p->cond != P) + if(!iscall(a) && p->link != P) { + q = brchain(p->link); + if(canfollow(a)) + if(q != P && (q->mark&FOLL)) { + p->as = relinv(a); + p->link = p->cond; + p->cond = q; + } + xfol(p->link); + q = brchain(p->cond); + if(q == P) + q = p->cond; + if(q->mark&FOLL) { + p->cond = q; + return; + } + p = q; + goto loop; + } + p = p->link; + goto loop; +} + +void +patch(void) +{ + long c, vexit; + Prog *p, *q; + Sym *s; + int a; + + if(debug['v']) + Bprint(&bso, "%5.2f patch\n", cputime()); + Bflush(&bso); + mkfwd(); + s = lookup("exit", 0); + vexit = s->value; + for(p = firstp; p != P; p = p->link) { + a = p->as; + if(a == ATEXT) + curtext = p; + if((iscall(a) || isbranch(a) || isreturn(a)) && + p->to.type != D_BRANCH && p->to.sym != S) { + s = p->to.sym; + switch(s->type) { + default: + diag("undefined: %s\n%P", s->name, p); + s->type = STEXT; + s->value = vexit; + break; + case STEXT: + p->to.offset = s->value; + break; + case SUNDEF: + if(!iscall(p->as)) + diag("help: SUNDEF in AB || ARET"); + p->to.offset = 0; + p->cond = UP; + break; + } + p->to.type = D_BRANCH; + } + if(p->cond == UP) + continue; + if(p->to.type == D_BRANCH) + c = p->to.offset; + else if(p->from.type == D_BRANCH) + c = p->from.offset; + else + continue; + for(q = firstp; q != P;) { + if(q->forwd != P) + if(c >= q->forwd->pc) { + q = q->forwd; + continue; + } + if(c == q->pc) + break; + q = q->link; + } + if(q == P) { + diag("branch out of range %ld\n%P", c, p); + p->to.type = D_NONE; + } + p->cond = q; + } + + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) + curtext = p; + if(p->cond != P && p->cond != UP) { + p->cond = brloop(p->cond); + if(p->cond != P){ + if(p->to.type == D_BRANCH) + p->to.offset = p->cond->pc; + if(p->from.type == D_BRANCH) + p->from.offset = p->cond->pc; + } + } + } +} + +#define LOG 6 +void +mkfwd(void) +{ + Prog *p; + long dwn[LOG], cnt[LOG], i; + Prog *lst[LOG]; + + for(i=0; ilink) { + if(p->as == ATEXT) + curtext = p; + i--; + if(i < 0) + i = LOG-1; + p->forwd = P; + dwn[i]--; + if(dwn[i] <= 0) { + dwn[i] = cnt[i]; + if(lst[i] != P) + lst[i]->forwd = p; + lst[i] = p; + } + } +} + +Prog* +brloop(Prog *p) +{ + Prog *q; + int c; + + for(c=0; p!=P;) { + if(!isbranch(p->as)) + return p; + q = p->cond; + if(q <= p) { + c++; + if(q == p || c > 5000) + break; + } + p = q; + } + return P; +} --- /dev/null +++ /sys/src/cmd/ld/pobj.c @@ -0,0 +1,485 @@ +#include "l.h" +#include + +char *noname = ""; +char symname[] = SYMDEF; + +char** libdir; +int nlibdir = 0; +static int maxlibdir = 0; + +int +isobjfile(char *f) +{ + int n, v; + Biobuf *b; + char buf1[5], buf2[SARMAG]; + + b = Bopen(f, OREAD); + if(b == nil) + return 0; + n = Bread(b, buf1, 5); + if(n == 5 && (buf1[2] == 1 && buf1[3] == '<' || buf1[3] == 1 && buf1[4] == '<')) + v = 1; /* good enough for our purposes */ + else{ + Bseek(b, 0, 0); + n = Bread(b, buf2, SARMAG); + v = n == SARMAG && strncmp(buf2, ARMAG, SARMAG) == 0; + } + Bterm(b); + return v; +} + +void +loadlib(void) +{ + int i; + long h; + Sym *s; + +loop: + xrefresolv = 0; + for(i=0; ilink) + if(s->type == SXREF) + goto loop; +} + +void +objfile(char *file) +{ + long off, esym, cnt, l; + int f, work; + Sym *s; + char magbuf[SARMAG]; + char name[LIBNAMELEN], pname[LIBNAMELEN]; + struct ar_hdr arhdr; + char *e, *start, *stop; + + if(debug['v']) + Bprint(&bso, "%5.2f ldobj: %s\n", cputime(), file); + Bflush(&bso); + if(file[0] == '-' && file[1] == 'l') { + snprint(pname, sizeof(pname), "lib%s.a", file+2); + e = findlib(pname); + if(e == nil) { + diag("cannot find library: %s", file); + errorexit(); + } + snprint(name, sizeof(name), "%s/%s", e, pname); + file = name; + } + f = open(file, 0); + if(f < 0) { + diag("cannot open %s: %r", file); + errorexit(); + } + l = read(f, magbuf, SARMAG); + if(l != SARMAG || strncmp(magbuf, ARMAG, SARMAG)){ + /* load it as a regular file */ + l = seek(f, 0L, 2); + seek(f, 0L, 0); + ldobj(f, l, file); + close(f); + return; + } + + if(debug['v']) + Bprint(&bso, "%5.2f ldlib: %s\n", cputime(), file); + l = read(f, &arhdr, SAR_HDR); + if(l != SAR_HDR) { + diag("%s: short read on archive file symbol header", file); + goto out; + } + if(strncmp(arhdr.name, symname, strlen(symname))) { + diag("%s: first entry not symbol header", file); + goto out; + } + + esym = SARMAG + SAR_HDR + atolwhex(arhdr.size); + off = SARMAG + SAR_HDR; + + /* + * just bang the whole symbol file into memory + */ + seek(f, off, 0); + cnt = esym - off; + start = malloc(cnt + 10); + cnt = read(f, start, cnt); + if(cnt <= 0){ + close(f); + return; + } + stop = &start[cnt]; + memset(stop, 0, 10); + + work = 1; + while(work){ + if(debug['v']) + Bprint(&bso, "%5.2f library pass: %s\n", cputime(), file); + Bflush(&bso); + work = 0; + for(e = start; e < stop; e = strchr(e+5, 0) + 1) { + s = lookup(e+5, 0); + if(s->type != SXREF) + continue; + sprint(pname, "%s(%s)", file, s->name); + if(debug['v']) + Bprint(&bso, "%5.2f library: %s\n", cputime(), pname); + Bflush(&bso); + l = e[1] & 0xff; + l |= (e[2] & 0xff) << 8; + l |= (e[3] & 0xff) << 16; + l |= (e[4] & 0xff) << 24; + seek(f, l, 0); + l = read(f, &arhdr, SAR_HDR); + if(l != SAR_HDR) + goto bad; + if(strncmp(arhdr.fmag, ARFMAG, sizeof(arhdr.fmag))) + goto bad; + l = atolwhex(arhdr.size); + ldobj(f, l, pname); + if(s->type == SXREF) { + diag("%s: failed to load: %s", file, s->name); + errorexit(); + } + work = 1; + xrefresolv = 1; + } + } + return; + +bad: + diag("%s: bad or out of date archive", file); +out: + close(f); +} + +void +addlibpath(char *arg) +{ + char **p; + + if(nlibdir >= maxlibdir) { + if(maxlibdir == 0) + maxlibdir = 8; + else + maxlibdir *= 2; + p = malloc(maxlibdir*sizeof(*p)); + if(p == nil) { + diag("out of memory"); + errorexit(); + } + memmove(p, libdir, nlibdir*sizeof(*p)); + free(libdir); + libdir = p; + } + libdir[nlibdir++] = strdup(arg); +} + +char* +findlib(char *file) +{ + int i; + char name[LIBNAMELEN]; + + for(i = 0; i < nlibdir; i++) { + snprint(name, sizeof(name), "%s/%s", libdir[i], file); + if(fileexists(name)) + return libdir[i]; + } + return nil; +} + +void +addlibroot(void) +{ + char *a; + char name[LIBNAMELEN]; + + a = getenv("ccroot"); + if(a != nil && *a != '\0') { + if(!fileexists(a)) { + diag("nonexistent $ccroot: %s", a); + errorexit(); + } + }else + a = ""; + snprint(name, sizeof(name), "%s/%s/lib", a, thestring); + addlibpath(name); +} + +void +addlib(char *obj) +{ + char fn1[LIBNAMELEN], fn2[LIBNAMELEN], comp[LIBNAMELEN], *p, *name; + int i, search; + + if(histfrogp <= 0) + return; + + name = fn1; + search = 0; + if(histfrog[0]->name[1] == '/') { + sprint(name, ""); + i = 1; + } else if(histfrog[0]->name[1] == '.') { + sprint(name, "."); + i = 0; + } else { + sprint(name, ""); + i = 0; + search = 1; + } + + for(; iname+1); + for(;;) { + p = strstr(comp, "$O"); + if(p == 0) + break; + memmove(p+1, p+2, strlen(p+2)+1); + p[0] = thechar; + } + for(;;) { + p = strstr(comp, "$M"); + if(p == 0) + break; + if(strlen(comp)+strlen(thestring)-2+1 >= sizeof comp) { + diag("library component too long"); + return; + } + memmove(p+strlen(thestring), p+2, strlen(p+2)+1); + memmove(p, thestring, strlen(thestring)); + } + if(strlen(fn1) + strlen(comp) + 3 >= sizeof(fn1)) { + diag("library component too long"); + return; + } + if(i > 0 || !search) + strcat(fn1, "/"); + strcat(fn1, comp); + } + + cleanname(name); + + if(search){ + p = findlib(name); + if(p != nil){ + snprint(fn2, sizeof(fn2), "%s/%s", p, name); + name = fn2; + } + } + + for(i=0; iname = malloc(2*(histfrogp+1) + 1); + + u->asym = s; + u->type = type; + u->aoffset = line; + u->link = curhist; + curhist = u; + + j = 1; + for(i=0; ivalue; + s->name[j+0] = k>>8; + s->name[j+1] = k; + j += 2; + } +} + +void +histtoauto(void) +{ + Auto *l; + + while((l = curhist) != nil) { + curhist = l->link; + l->link = curauto; + curauto = l; + } +} + +void +collapsefrog(Sym *s) +{ + int i; + + /* + * bad encoding of path components only allows + * MAXHIST components. if there is an overflow, + * first try to collapse xxx/.. + */ + for(i=1; iname+1, "..") == 0) { + memmove(histfrog+i-1, histfrog+i+1, + (histfrogp-i-1)*sizeof(histfrog[0])); + histfrogp--; + goto out; + } + + /* + * next try to collapse . + */ + for(i=0; iname+1, ".") == 0) { + memmove(histfrog+i, histfrog+i+1, + (histfrogp-i-1)*sizeof(histfrog[0])); + goto out; + } + + /* + * last chance, just truncate from front + */ + memmove(histfrog+0, histfrog+1, + (histfrogp-1)*sizeof(histfrog[0])); + +out: + histfrog[histfrogp-1] = s; +} + +uchar* +readsome(int f, uchar *buf, uchar *good, uchar *stop, int max) +{ + int n; + + n = stop - good; + memmove(buf, good, stop - good); + stop = buf + n; + n = MAXIO - n; + if(n > max) + n = max; + n = read(f, stop, n); + if(n <= 0) + return 0; + return stop + n; +} + +Sym* +lookup(char *symb, int v) +{ + Sym *s; + char *p; + long h; + int c, l; + + h = v; + for(p=symb; c = *p; p++) + h = h+h+h + c; + l = (p - symb) + 1; + if(h < 0) + h = ~h; + h %= NHASH; + for(s = hash[h]; s != S; s = s->link) + if(s->version == v) + if(memcmp(s->name, symb, l) == 0) + return s; + + s = halloc(sizeof(Sym)); + s->name = malloc(l + 1); + memmove(s->name, symb, l); + + s->link = hash[h]; + s->type = 0; + s->version = v; + s->value = 0; + s->sig = 0; + hash[h] = s; + return s; +} + +int +find1(long l, int c) +{ + char *p; + int i; + + p = (char*)&l; + for(i=0; i<4; i++) + if(*p++ == c) + return i; + return 0; +} + +long +ieeedtof(Ieee *ieeep) +{ + int exp; + long v; + + if(ieeep->h == 0) + return 0; + exp = (ieeep->h>>20) & ((1L<<11)-1L); + exp -= (1L<<10) - 2L; + v = (ieeep->h & 0xfffffL) << 3; + v |= (ieeep->l >> 29) & 0x7L; + if((ieeep->l >> 28) & 1) { + v++; + if(v & 0x800000L) { + v = (v & 0x7fffffL) >> 1; + exp++; + } + } + if(exp <= -126 || exp >= 130) + diag("double fp to single fp overflow"); + v |= ((exp + 126) & 0xffL) << 23; + v |= ieeep->h & 0x80000000L; + return v; +} + +double +ieeedtod(Ieee *ieeep) +{ + Ieee e; + double fr; + int exp; + + if(ieeep->h & (1L<<31)) { + e.h = ieeep->h & ~(1L<<31); + e.l = ieeep->l; + return -ieeedtod(&e); + } + if(ieeep->l == 0 && ieeep->h == 0) + return 0; + fr = ieeep->l & ((1L<<16)-1L); + fr /= 1L<<16; + fr += (ieeep->l>>16) & ((1L<<16)-1L); + fr /= 1L<<16; + fr += (ieeep->h & (1L<<20)-1L) | (1L<<20); + fr /= 1L<<21; + exp = (ieeep->h>>20) & ((1L<<11)-1L); + exp -= (1L<<10) - 2L; + return ldexp(fr, exp); +} --- /dev/null +++ /sys/src/cmd/ld/sub.c @@ -0,0 +1,264 @@ +#include "l.h" + +static usize nhunk; +static usize tothunk; +static char* hunk; + +void +diag(char *fmt, ...) +{ + char buf[STRINGSZ], *tn; + va_list arg; + + tn = "??none??"; + if(curtext != P && curtext->from.sym != S) + tn = curtext->from.sym->name; + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + print("%s: %s\n", tn, buf); + + nerrors++; + if(nerrors > 10) { + print("too many errors\n"); + errorexit(); + } +} + +void +errorexit(void) +{ + + if(nerrors) { + if(cout >= 0) + remove(outfile); + exits("error"); + } + exits(0); +} + +void +prasm(Prog *p) +{ + print("%P\n", p); +} + +int +Sconv(Fmt *fp) +{ + int i, c; + char str[STRINGSZ], *p, *a; + + a = va_arg(fp->args, char*); + p = str; + for(i=0; i= 'a' && c <= 'z' || + c >= 'A' && c <= 'Z' || + c >= '0' && c <= '9' || + c == ' ' || c == '%') { + *p++ = c; + continue; + } + *p++ = '\\'; + switch(c) { + case 0: + *p++ = 'z'; + continue; + case '\\': + case '"': + *p++ = c; + continue; + case '\n': + *p++ = 'n'; + continue; + case '\t': + *p++ = 't'; + continue; + } + *p++ = (c>>6) + '0'; + *p++ = ((c>>3) & 7) + '0'; + *p++ = (c & 7) + '0'; + } + *p = 0; + return fmtstrcpy(fp, str); +} + +void +nopstat(char *f, Count *c) +{ + if(c->outof) + Bprint(&bso, "%s delay %ld/%ld (%.2f)\n", f, + c->outof - c->count, c->outof, + (double)(c->outof - c->count)/c->outof); +} + +void +xdefine(char *p, int t, vlong v) +{ + Sym *s; + + s = lookup(p, 0); + if(s->type == 0 || s->type == SXREF) { + s->type = t; + s->value = v; + } +} + +void +undef(void) +{ + int i; + Sym *s; + + for(i=0; ilink) + if(s->type == SXREF) + diag("%s: not defined", s->name); +} + +vlong +atolwhex(char *s) +{ + vlong n; + int f; + + n = 0; + f = 0; + while(*s == ' ' || *s == '\t') + s++; + if(*s == '-' || *s == '+') { + if(*s++ == '-') + f = 1; + while(*s == ' ' || *s == '\t') + s++; + } + if(s[0]=='0' && s[1]){ + if(s[1]=='x' || s[1]=='X'){ + s += 2; + for(;;){ + if(*s >= '0' && *s <= '9') + n = n*16 + *s++ - '0'; + else if(*s >= 'a' && *s <= 'f') + n = n*16 + *s++ - 'a' + 10; + else if(*s >= 'A' && *s <= 'F') + n = n*16 + *s++ - 'A' + 10; + else + break; + } + } else + while(*s >= '0' && *s <= '7') + n = n*8 + *s++ - '0'; + } else + while(*s >= '0' && *s <= '9') + n = n*10 + *s++ - '0'; + if(f) + n = -n; + return n; +} + +vlong +rnd(vlong v, long r) +{ + long c; + + if(r <= 0) + return v; + v += r - 1; + c = v % r; + if(c < 0) + c += r; + v -= c; + return v; +} + +Prog* +prg(void) +{ + Prog *p; + + while(nhunk < sizeof(Prog)) + gethunk(); + p = (Prog*)hunk; + nhunk -= sizeof(Prog); + hunk += sizeof(Prog); + + *p = zprg; + return p; +} + +void* +halloc(usize n) +{ + void *p; + + n = (n+7)&~7; + while(nhunk < n) + gethunk(); + p = hunk; + nhunk -= n; + hunk += n; + return p; +} + +void +gethunk(void) +{ + char *h; + long nh; + + nh = NHUNK; + if(tothunk >= 5L*NHUNK) { + nh = 5L*NHUNK; + if(tothunk >= 25L*NHUNK) + nh = 25L*NHUNK; + } + h = mysbrk(nh); + if(h == (void*)-1) { + diag("out of memory"); + errorexit(); + } + + hunk = h; + nhunk = nh; + tothunk += nh; +} + +long +hunkspace(void) +{ + return tothunk; +} + +void +strnput(char *s, int n) +{ + for(; *s; s++){ + cput(*s); + n--; + } + for(; n > 0; n--) + cput(0); +} + +void +cput(int c) +{ + cbp[0] = c; + cbp++; + cbc--; + if(cbc <= 0) + cflush(); +} + +void +cflush(void) +{ + int n; + + n = sizeof(buf.cbuf) - cbc; + if(n) + write(cout, buf.cbuf, n); + cbp = buf.cbuf; + cbc = sizeof(buf.cbuf); +}