diff -r d8d00747375b 386/include/u.h --- a/386/include/u.h Thu Sep 29 03:00:00 2011 +0200 +++ b/386/include/u.h Mon Nov 14 17:35:25 2011 +0100 @@ -20,6 +20,17 @@ typedef unsigned int u32int; typedef unsigned long long u64int; +/* Go */ +#include +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned int uint32; +typedef unsigned long long uint64; +typedef char int8; +typedef short int16; +typedef int int32; +typedef long long int64; + /* FCR */ #define FPINEX (1<<5) #define FPUNFL ((1<<4)|(1<<1)) diff -r d8d00747375b sys/include/bio.h --- a/sys/include/bio.h Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/include/bio.h Mon Nov 14 17:35:25 2011 +0100 @@ -2,7 +2,6 @@ #pragma lib "libbio.a" typedef struct Biobuf Biobuf; -typedef struct Biobufhdr Biobufhdr; enum { @@ -16,9 +15,11 @@ Bractive, Bwactive, Bracteof, + + Bend }; -struct Biobufhdr +struct Biobuf { int icount; /* neg num of bytes at eob */ int ocount; /* num of bytes at bob */ @@ -32,43 +33,47 @@ uchar* bbuf; /* pointer to beginning of buffer */ uchar* ebuf; /* pointer to end of buffer */ uchar* gbuf; /* pointer to good data in buf */ -}; - -struct Biobuf -{ - Biobufhdr; uchar b[Bungetsize+Bsize]; }; -/* Dregs, redefined as functions for backwards compatibility */ -#define BGETC(bp) Bgetc(bp) -#define BPUTC(bp,c) Bputc(bp,c) -#define BOFFSET(bp) Boffset(bp) -#define BLINELEN(bp) Blinelen(bp) -#define BFILDES(bp) Bfildes(bp) +#define BGETC(bp)\ + ((bp)->icount?(bp)->bbuf[(bp)->bsize+(bp)->icount++]:Bgetc((bp))) +#define BPUTC(bp,c)\ + ((bp)->ocount?(bp)->bbuf[(bp)->bsize+(bp)->ocount++]=(c),0:Bputc((bp),(c))) +#define BOFFSET(bp)\ + (((bp)->state==Bractive)?\ + (bp)->offset + (bp)->icount:\ + (((bp)->state==Bwactive)?\ + (bp)->offset + ((bp)->bsize + (bp)->ocount):\ + -1)) +#define BLINELEN(bp)\ + (bp)->rdline +#define BFILDES(bp)\ + (bp)->fid -int Bbuffered(Biobufhdr*); -int Bfildes(Biobufhdr*); -int Bflush(Biobufhdr*); -int Bgetc(Biobufhdr*); -int Bgetd(Biobufhdr*, double*); -long Bgetrune(Biobufhdr*); +int Bbuffered(Biobuf*); +Biobuf* Bfdopen(int, int); +int Bfildes(Biobuf*); +int Bflush(Biobuf*); +int Bgetc(Biobuf*); +int Bgetd(Biobuf*, double*); +long Bgetrune(Biobuf*); int Binit(Biobuf*, int, int); -int Binits(Biobufhdr*, int, int, uchar*, int); -int Blinelen(Biobufhdr*); -vlong Boffset(Biobufhdr*); +int Binits(Biobuf*, int, int, uchar*, int); +int Blinelen(Biobuf*); +vlong Boffset(Biobuf*); Biobuf* Bopen(char*, int); -int Bprint(Biobufhdr*, char*, ...); -int Bvprint(Biobufhdr*, char*, va_list); -int Bputc(Biobufhdr*, int); -int Bputrune(Biobufhdr*, long); -void* Brdline(Biobufhdr*, int); -char* Brdstr(Biobufhdr*, int, int); -long Bread(Biobufhdr*, void*, long); -vlong Bseek(Biobufhdr*, vlong, int); -int Bterm(Biobufhdr*); -int Bungetc(Biobufhdr*); -int Bungetrune(Biobufhdr*); -long Bwrite(Biobufhdr*, void*, long); +int Bprint(Biobuf*, char*, ...); +int Bputc(Biobuf*, int); +int Bputrune(Biobuf*, long); +void* Brdline(Biobuf*, int); +char* Brdstr(Biobuf*, int, int); +long Bread(Biobuf*, void*, long); +vlong Bseek(Biobuf*, vlong, int); +int Bterm(Biobuf*); +int Bungetc(Biobuf*); +int Bungetrune(Biobuf*); +long Bwrite(Biobuf*, void*, long); +int Bvprint(Biobuf*, char*, va_list); #pragma varargck argpos Bprint 2 diff -r d8d00747375b sys/include/libc.h --- a/sys/include/libc.h Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/include/libc.h Mon Nov 14 17:35:25 2011 +0100 @@ -677,6 +677,11 @@ extern int wstat(char*, uchar*, int); extern void* rendezvous(void*, void*); +extern char* getgoos(void); +extern char* getgoarch(void); +extern char* getgoroot(void); +extern char* getgoversion(void); + extern Dir* dirstat(char*); extern Dir* dirfstat(int); extern int dirwstat(char*, Dir*); diff -r d8d00747375b sys/src/cmd/5a/a.h --- a/sys/src/cmd/5a/a.h Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/5a/a.h Mon Nov 14 17:35:25 2011 +0100 @@ -1,12 +1,47 @@ -#include -#include +// Inferno utils/5a/a.h +// http://code.google.com/p/inferno-os/source/browse/utils/5a/a.h +// +// 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 -#include "../5c/5.out.h" +#include "../5l/5.out.h" #ifndef EXTERN #define EXTERN extern #endif +#undef getc +#undef ungetc +#undef BUFSIZ + +#define getc ccgetc +#define ungetc ccungetc + typedef struct Sym Sym; typedef struct Gen Gen; typedef struct Io Io; @@ -17,9 +52,9 @@ #define NSYMB 8192 #define BUFSIZ 8192 #define HISTSZ 20 -#define NINCLUDE 10 -#define NHUNK 10000 +#ifndef EOF #define EOF (-1) +#endif #define IGN (-2) #define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff) #define NHASH 503 @@ -30,7 +65,7 @@ { Sym* link; char* macro; - long value; + int32 value; ushort type; char *name; char sym; @@ -62,7 +97,7 @@ struct Gen { Sym* sym; - long offset; + int32 offset; short type; short reg; short name; @@ -74,8 +109,8 @@ { Hist* link; char* name; - long line; - long offset; + int32 line; + int32 offset; }; #define H ((Hist*)0) @@ -91,35 +126,38 @@ EXTERN char debug[256]; EXTERN Sym* hash[NHASH]; -EXTERN char* Dlist[30]; +EXTERN char** Dlist; EXTERN int nDlist; EXTERN Hist* ehist; EXTERN int newflag; EXTERN Hist* hist; EXTERN char* hunk; -EXTERN char* include[NINCLUDE]; +EXTERN char** include; EXTERN Io* iofree; EXTERN Io* ionext; EXTERN Io* iostack; -EXTERN long lineno; +EXTERN int32 lineno; EXTERN int nerrors; -EXTERN long nhunk; +EXTERN int32 nhunk; EXTERN int ninclude; +EXTERN int32 nsymb; EXTERN Gen nullgen; EXTERN char* outfile; EXTERN int pass; EXTERN char* pathname; -EXTERN long pc; +EXTERN int32 pc; EXTERN int peekc; +EXTERN int32 stmtline; EXTERN int sym; -EXTERN char symb[NSYMB]; +EXTERN char* symb; EXTERN int thechar; EXTERN char* thestring; -EXTERN long thunk; +EXTERN int32 thunk; EXTERN Biobuf obuf; -void* alloc(long); -void* allocn(void*, long, long); +void* alloc(int32); +void* allocn(void*, int32, int32); +void ensuresymb(int32); void errorexit(void); void pushio(void); void newio(void); @@ -127,7 +165,7 @@ Sym* slookup(char*); Sym* lookup(void); void syminit(Sym*); -long yylex(void); +int32 yylex(void); int getc(void); int getnsc(void); void unget(int); @@ -153,31 +191,10 @@ void macend(void); void outhist(void); void dodefine(char*); -void prfile(long); +void prfile(int32); void linehist(char*, int); void gethunk(void); void yyerror(char*, ...); int yyparse(void); void setinclude(char*); int assemble(char*); - -/* - * system-dependent stuff from ../cc/compat.c - */ - -enum /* keep in synch with ../cc/cc.h */ -{ - Plan9 = 1<<0, - Unix = 1<<1, - Windows = 1<<2, -}; -int mywait(int*); -int mycreat(char*, int); -int systemtype(int); -int pathchar(void); -char* mygetwd(char*, int); -int myexec(char*, char*[]); -int mydup(int, int); -int myfork(void); -int mypipe(int*); -void* mysbrk(ulong); diff -r d8d00747375b sys/src/cmd/5a/a.y --- a/sys/src/cmd/5a/a.y Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/5a/a.y Mon Nov 14 17:35:25 2011 +0100 @@ -1,10 +1,43 @@ +// Inferno utils/5a/a.y +// http://code.google.com/p/inferno-os/source/browse/utils/5a/a.y +// +// 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 +#include /* if we don't, bison will, and a.h re-#defines getc */ +#include #include "a.h" %} %union { Sym *sym; - long lval; + int32 lval; double dval; char sval[8]; Gen gen; @@ -32,7 +65,11 @@ %type imm ximm name oreg ireg nireg ioreg imsr %% prog: -| prog line +| prog + { + stmtline = lineno; + } + line line: LLAB ':' @@ -258,7 +295,7 @@ /* * MULA hi,lo,r1,r2 */ -| LTYPEN cond reg ',' reg ',' reg ',' spreg +| LTYPEN cond reg ',' reg ',' reg ',' spreg { $7.type = D_REGREG; $7.offset = $9; diff -r d8d00747375b sys/src/cmd/5a/l.s --- a/sys/src/cmd/5a/l.s Thu Sep 29 03:00:00 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -TEXT main(SB), $0 - - ADD R1,R4 - ADD R1,R3,R4 - ADD R1<<1,R3,R4 /* logical left */ - ADD R1>>1,R3,R4 /* logical right */ - ADD R1->1,R3,R4 /* arithmetic right */ - ADD R1@>1,R3,R4 /* rotate right */ - - ADD R1< +#include #include "a.h" #include "y.tab.h" -#include + +enum +{ + Plan9 = 1<<0, + Unix = 1<<1, + Windows = 1<<2, +}; + +int +systemtype(int sys) +{ +#ifdef _WIN32 + return sys&Windows; +#else + return sys&Plan9; +#endif +} void main(int argc, char *argv[]) { char *p; - int nout, nproc, status, i, c; + int c; thechar = '5'; thestring = "arm"; + + ensuresymb(NSYMB); memset(debug, 0, sizeof(debug)); cinit(); outfile = 0; - include[ninclude++] = "."; + setinclude("."); ARGBEGIN { default: c = ARGC(); @@ -28,8 +78,12 @@ case 'D': p = ARGF(); - if(p) + if(p) { + if (nDlist%8 == 0) + Dlist = allocn(Dlist, nDlist*sizeof(char *), + 8*sizeof(char *)); Dlist[nDlist++] = p; + } break; case 'I': @@ -45,49 +99,10 @@ print("usage: %ca [-options] file.s\n", thechar); errorexit(); } - if(argc > 1 && systemtype(Windows)){ - print("can't assemble multiple files on windows\n"); + if(argc > 1){ + print("can't assemble multiple files\n"); errorexit(); } - if(argc > 1 && !systemtype(Windows)) { - nproc = 1; - if(p = getenv("NPROC")) - nproc = atol(p); /* */ - c = 0; - nout = 0; - for(;;) { - while(nout < nproc && argc > 0) { - i = myfork(); - if(i < 0) { - i = mywait(&status); - if(i < 0) - errorexit(); - if(status) - c++; - nout--; - continue; - } - if(i == 0) { - print("%s:\n", *argv); - if(assemble(*argv)) - errorexit(); - exits(0); - } - nout++; - argc--; - argv++; - } - i = mywait(&status); - if(i < 0) { - if(c) - errorexit(); - exits(0); - } - if(status) - c++; - nout--; - } - } if(assemble(argv[0])) errorexit(); exits(0); @@ -96,11 +111,12 @@ int assemble(char *file) { - char ofile[100], incfile[20], *p; + char *ofile, incfile[20], *p; int i, of; + ofile = alloc(strlen(file)+3); // +3 for .x\0 (x=thechar) strcpy(ofile, file); - p = utfrrune(ofile, pathchar()); + p = utfrrune(ofile, '/'); if(p) { include[0] = ofile; *p++ = 0; @@ -130,7 +146,7 @@ } } - of = mycreat(outfile, 0664); + of = create(outfile, OWRITE, 0664); if(of < 0) { yyerror("%ca: cannot create %s", thechar, outfile); errorexit(); @@ -139,6 +155,9 @@ pass = 1; pinit(file); + + Bprint(&obuf, "go object %s %s %s\n", getgoos(), thestring, getgoversion()); + for(i=0; i>8); - Bputc(&obuf, lineno>>16); - Bputc(&obuf, lineno>>24); + Bputc(&obuf, stmtline); + Bputc(&obuf, stmtline>>8); + Bputc(&obuf, stmtline>>16); + Bputc(&obuf, stmtline>>24); zaddr(g1, sf); zaddr(g2, st); @@ -624,21 +652,17 @@ int n; g = nullgen; - c = pathchar(); + c = '/'; for(h = hist; h != H; h = h->link) { p = h->name; op = 0; - /* on windows skip drive specifier in pathname */ if(systemtype(Windows) && p && p[1] == ':'){ - p += 2; - c = *p; - } - if(p && p[0] != c && h->offset == 0 && pathname){ - /* on windows skip drive specifier in pathname */ + c = p[2]; + } else if(p && p[0] != c && h->offset == 0 && pathname){ if(systemtype(Windows) && pathname[1] == ':') { op = p; - p = pathname+2; - c = *p; + p = pathname; + c = p[2]; } else if(pathname[0] == c){ op = p; p = pathname; @@ -687,4 +711,3 @@ #include "../cc/lexbody" #include "../cc/macbody" -#include "../cc/compat" diff -r d8d00747375b sys/src/cmd/5a/mkfile --- a/sys/src/cmd/5a/mkfile Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/5a/mkfile Mon Nov 14 17:35:25 2011 +0100 @@ -6,7 +6,7 @@ lex.$O\ HFILES=\ - ../5c/5.out.h\ + ../5l/5.out.h\ y.tab.h\ a.h\ @@ -16,4 +16,4 @@ < /sys/src/cmd/mkone YFLAGS=-D1 -d -lex.$O: ../cc/macbody ../cc/lexbody ../cc/compat +lex.$O: ../cc/macbody ../cc/lexbody diff -r d8d00747375b sys/src/cmd/5c/5.out.h --- a/sys/src/cmd/5c/5.out.h Thu Sep 29 03:00:00 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,199 +0,0 @@ -#define NSNAME 8 -#define NSYM 50 -#define NREG 16 - -#define NOPROF (1<<0) -#define DUPOK (1<<1) -#define ALLTHUMBS (1<<2) - -#define REGRET 0 -#define REGARG 0 -/* compiler allocates R1 up as temps */ -/* compiler allocates register variables R2 up */ -#define REGMIN 2 -#define REGMAX 8 -#define REGEXT 10 -/* compiler allocates external registers R10 down */ -#define REGTMP 11 -#define REGSB 12 -#define REGSP 13 -#define REGLINK 14 -#define REGPC 15 - -#define REGTMPT 7 /* used by the loader for thumb code */ - -#define NFREG 8 -#define FREGRET 0 -#define FREGEXT 7 -/* compiler allocates register variables F0 up */ -/* compiler allocates external registers F7 down */ - -enum as -{ - AXXX, - - AAND, - AEOR, - ASUB, - ARSB, - AADD, - AADC, - ASBC, - ARSC, - ATST, - ATEQ, - ACMP, - ACMN, - AORR, - ABIC, - - AMVN, - - AB, - ABL, - -/* - * Do not reorder or fragment the conditional branch - * opcodes, or the predication code will break - */ - ABEQ, - ABNE, - ABCS, - ABHS, - ABCC, - ABLO, - ABMI, - ABPL, - ABVS, - ABVC, - ABHI, - ABLS, - ABGE, - ABLT, - ABGT, - ABLE, - - AMOVWD, - AMOVWF, - AMOVDW, - AMOVFW, - AMOVFD, - AMOVDF, - AMOVF, - AMOVD, - - ACMPF, - ACMPD, - AADDF, - AADDD, - ASUBF, - ASUBD, - AMULF, - AMULD, - ADIVF, - ADIVD, - - ASRL, - ASRA, - ASLL, - AMULU, - ADIVU, - AMUL, - ADIV, - AMOD, - AMODU, - - AMOVB, - AMOVBU, - AMOVH, - AMOVHU, - AMOVW, - AMOVM, - ASWPBU, - ASWPW, - - ANOP, - ARFE, - ASWI, - AMULA, - - ADATA, - AGLOBL, - AGOK, - AHISTORY, - ANAME, - ARET, - ATEXT, - AWORD, - ADYNT, - AINIT, - ABCASE, - ACASE, - - AEND, - - AMULL, - AMULAL, - AMULLU, - AMULALU, - - ABX, - ABXRET, - ADWORD, - - ASIGNAME, - - ALAST, -}; - -/* scond byte */ -#define C_SCOND ((1<<4)-1) -#define C_SBIT (1<<4) -#define C_PBIT (1<<5) -#define C_WBIT (1<<6) -#define C_FBIT (1<<7) /* psr flags-only */ -#define C_UBIT (1<<7) /* up bit */ - -/* type/name */ -#define D_GOK 0 -#define D_NONE 1 - -/* type */ -#define D_BRANCH (D_NONE+1) -#define D_OREG (D_NONE+2) -#define D_CONST (D_NONE+7) -#define D_FCONST (D_NONE+8) -#define D_SCONST (D_NONE+9) -#define D_PSR (D_NONE+10) -#define D_REG (D_NONE+12) -#define D_FREG (D_NONE+13) -#define D_FILE (D_NONE+16) -#define D_OCONST (D_NONE+17) -#define D_FILE1 (D_NONE+18) - -#define D_SHIFT (D_NONE+19) -#define D_FPCR (D_NONE+20) -#define D_REGREG (D_NONE+21) - -/* name */ -#define D_EXTERN (D_NONE+3) -#define D_STATIC (D_NONE+4) -#define D_AUTO (D_NONE+5) -#define D_PARAM (D_NONE+6) - -/* - * this is the ranlib header - */ -#define SYMDEF "__.SYMDEF" - -/* - * this is the simulated IEEE floating point - */ -typedef struct ieee Ieee; -struct ieee -{ - long l; /* contains ls-man 0xffffffff */ - long h; /* contains sign 0x80000000 - exp 0x7ff00000 - ms-man 0x000fffff */ -}; diff -r d8d00747375b sys/src/cmd/5c/cgen.c --- a/sys/src/cmd/5c/cgen.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/5c/cgen.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,19 +1,44 @@ +// Inferno utils/5c/cgen.c +// http://code.google.com/p/inferno-os/source/browse/utils/5c/cgen.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 "gc.h" void -cgen(Node *n, Node *nn) -{ - cgenrel(n, nn, 0); -} - -void -cgenrel(Node *n, Node *nn, int inrel) +_cgen(Node *n, Node *nn, int inrel) { Node *l, *r; Prog *p1; Node nod, nod1, nod2, nod3, nod4; int o, t; - long v, curs; + int32 v, curs; if(debug['g']) { prtree(nn, "cgen lhs"); @@ -248,7 +273,7 @@ gopcode(OAS, &nod2, Z, &nod); gopcode(o, r, Z, &nod); gopcode(OAS, &nod, Z, &nod2); - + regfree(&nod); if(l->addable < INDEXED) regfree(&nod2); @@ -451,7 +476,7 @@ diag(n, "DOT and no offset"); break; } - nod.xoffset += (long)r->vconst; + nod.xoffset += (int32)r->vconst; nod.type = n->type; cgen(&nod, nn); } @@ -539,8 +564,6 @@ } else gopcode(OADD, nodconst(v), Z, &nod); gopcode(OAS, &nod, Z, &nod2); - if(nn && l->op == ONAME) /* in x=++i, emit USED(i) */ - gins(ANOP, l, Z); regfree(&nod); if(l->addable < INDEXED) @@ -565,10 +588,22 @@ } void +cgen(Node *n, Node *nn) +{ + _cgen(n, nn, 0); +} + +void +cgenrel(Node *n, Node *nn) +{ + _cgen(n, nn, 1); +} + +void reglcgen(Node *t, Node *n, Node *nn) { Node *r; - long v; + int32 v; regialloc(t, n, nn); if(n->op == OIND) { @@ -683,7 +718,7 @@ int o; Prog *p1, *p2; Node *l, *r, nod, nod1; - long curs; + int32 curs; if(debug['g']) { prtree(nn, "boolgen lhs"); @@ -787,7 +822,7 @@ o = comrel[relindex(o)]; if(l->complex >= FNX && r->complex >= FNX) { regret(&nod, r); - cgenrel(r, &nod, 1); + cgenrel(r, &nod); regsalloc(&nod1, r); gopcode(OAS, &nod, Z, &nod1); regfree(&nod); @@ -798,7 +833,7 @@ } if(sconst(l)) { regalloc(&nod, r, nn); - cgenrel(r, &nod, 1); + cgenrel(r, &nod); o = invrel[relindex(o)]; gopcode(o, l, &nod, Z); regfree(&nod); @@ -806,21 +841,21 @@ } if(sconst(r)) { regalloc(&nod, l, nn); - cgenrel(l, &nod, 1); + cgenrel(l, &nod); gopcode(o, r, &nod, Z); regfree(&nod); goto com; } if(l->complex >= r->complex) { regalloc(&nod1, l, nn); - cgenrel(l, &nod1, 1); + cgenrel(l, &nod1); regalloc(&nod, r, Z); - cgenrel(r, &nod, 1); + cgenrel(r, &nod); } else { regalloc(&nod, r, nn); - cgenrel(r, &nod, 1); + cgenrel(r, &nod); regalloc(&nod1, l, Z); - cgenrel(l, &nod1, 1); + cgenrel(l, &nod1); } gopcode(o, &nod, &nod1, Z); regfree(&nod); @@ -842,12 +877,12 @@ } void -sugen(Node *n, Node *nn, long w) +sugen(Node *n, Node *nn, int32 w) { Prog *p1; Node nod0, nod1, nod2, nod3, nod4, *l, *r; Type *t; - long pc1; + int32 pc1; int i, m, c; if(n == Z || n->type == T) @@ -881,12 +916,12 @@ reglcgen(&nod1, nn, Z); nn->type = t; - if(align(0, types[TCHAR], Aarg1)) /* isbigendian */ + if(isbigendian) gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1); else gopcode(OAS, nod32const(n->vconst), Z, &nod1); nod1.xoffset += SZ_LONG; - if(align(0, types[TCHAR], Aarg1)) /* isbigendian */ + if(isbigendian) gopcode(OAS, nod32const(n->vconst), Z, &nod1); else gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1); @@ -907,7 +942,7 @@ diag(n, "DOT and no offset"); break; } - nod1.xoffset += (long)r->vconst; + nod1.xoffset += (int32)r->vconst; nod1.type = n->type; sugen(&nod1, nn, w); } @@ -1071,10 +1106,6 @@ } regalloc(&nod3, ®node, Z); regalloc(&nod4, ®node, Z); - if(nod3.reg > nod4.reg){ - /* code below assumes nod3 loaded first */ - Node t = nod3; nod3 = nod4; nod4 = t; - } nod0 = *nodconst((1< #include "../cc/cc.h" -#include "../5c/5.out.h" +#include "../5l/5.out.h" /* * 5c/arm @@ -30,14 +61,15 @@ struct Adr { - long offset; + int32 offset; + int32 offset2; double dval; char sval[NSNAME]; Ieee ieee; Sym* sym; char type; - char reg; + uchar reg; char name; char etype; }; @@ -49,9 +81,9 @@ Adr from; Adr to; Prog* link; - long lineno; + int32 lineno; char as; - char reg; + uchar reg; uchar scond; }; #define P ((Prog*)0) @@ -59,22 +91,22 @@ struct Case { Case* link; - long val; - long label; + int32 val; + int32 label; char def; - char isv; + char isv; }; #define C ((Case*)0) struct C1 { - long val; - long label; + int32 val; + int32 label; }; struct Multab { - long val; + int32 val; char code[20]; }; @@ -86,7 +118,7 @@ struct Var { - long offset; + int32 offset; Sym* sym; char name; char etype; @@ -94,8 +126,8 @@ struct Reg { - long pc; - long rpo; /* reverse post ordering */ + int32 pc; + int32 rpo; /* reverse post ordering */ Bits set; Bits use1; @@ -108,12 +140,12 @@ Bits regdiff; Bits act; - long regu; - long loop; /* could be shorter */ + int32 regu; + int32 loop; /* could be shorter */ - + Reg* log5; - long active; + int32 active; Reg* p1; Reg* p2; @@ -134,35 +166,37 @@ short regno; }; -EXTERN long breakpc; -EXTERN long nbreak; +EXTERN int32 breakpc; +EXTERN int32 nbreak; EXTERN Case* cases; EXTERN Node constnode; EXTERN Node fconstnode; -EXTERN long continpc; -EXTERN long curarg; -EXTERN long cursafe; +EXTERN int32 continpc; +EXTERN int32 curarg; +EXTERN int32 cursafe; EXTERN Prog* firstp; +EXTERN int32 isbigendian; EXTERN Prog* lastp; -EXTERN long maxargsafe; +EXTERN int32 maxargsafe; EXTERN int mnstring; EXTERN Multab multab[20]; -EXTERN int hintabsize; +EXTERN int retok; +extern int hintabsize; EXTERN Node* nodrat; EXTERN Node* nodret; EXTERN Node* nodsafe; -EXTERN long nrathole; -EXTERN long nstring; +EXTERN int32 nrathole; +EXTERN int32 nstring; EXTERN Prog* p; -EXTERN long pc; +EXTERN int32 pc; EXTERN Node regnode; EXTERN char string[NSNAME]; EXTERN Sym* symrathole; EXTERN Node znode; EXTERN Prog zprog; EXTERN char reg[NREG+NFREG]; -EXTERN long exregoffset; -EXTERN long exfregoffset; +EXTERN int32 exregoffset; +EXTERN int32 exfregoffset; EXTERN int suppress; #define BLOAD(r) band(bnot(r->refbehind), r->refahead) @@ -187,8 +221,8 @@ EXTERN Bits consts; EXTERN Bits addrs; -EXTERN long regbits; -EXTERN long exregbits; +EXTERN int32 regbits; +EXTERN int32 exregbits; EXTERN int change; @@ -197,9 +231,9 @@ EXTERN Reg zreg; EXTERN Reg* freer; EXTERN Var var[NVAR]; -EXTERN long* idom; +EXTERN int32* idom; EXTERN Reg** rpo2r; -EXTERN long maxnr; +EXTERN int32 maxnr; extern char* anames[]; extern Hintab hintab[]; @@ -213,18 +247,20 @@ void usedset(Node*, int); void xcom(Node*); int bcomplex(Node*, Node*); +Prog* gtext(Sym*, int32); +vlong argsize(void); /* * cgen.c */ void cgen(Node*, Node*); -void cgenrel(Node*, Node*, int); void reglcgen(Node*, Node*, Node*); void lcgen(Node*, Node*); void bcgen(Node*, int); void boolgen(Node*, int, Node*); -void sugen(Node*, Node*, long); +void sugen(Node*, Node*, int32); void layout(Node*, Node*, int, int, Node*); +void cgenrel(Node*, Node*); /* * txt.c @@ -234,7 +270,7 @@ void nextpc(void); void gargs(Node*, Node*, Node*); void garg1(Node*, Node*, Node*, int, Node**); -Node* nodconst(long); +Node* nodconst(int32); Node* nod32const(vlong); Node* nodfconst(double); void nodreg(Node*, Node*, int); @@ -257,9 +293,9 @@ void gopcode(int, Node*, Node*, Node*); int samaddr(Node*, Node*); void gbranch(int); -void patch(Prog*, long); +void patch(Prog*, int32); int sconst(Node*); -int sval(long); +int sval(int32); void gpseudo(int, Sym*, Node*); /* @@ -267,17 +303,13 @@ */ int swcmp(const void*, const void*); void doswit(Node*); -void swit1(C1*, int, long, Node*); -void swit2(C1*, int, long, Node*, Node*); -void casf(void); +void swit1(C1*, int, int32, Node*); +void newcase(void); void bitload(Node*, Node*, Node*, Node*, Node*); void bitstore(Node*, Node*, Node*, Node*, Node*); -long outstring(char*, long); int mulcon(Node*, Node*); -Multab* mulcon0(long); +Multab* mulcon0(int32); void nullwarn(Node*, Node*); -void sextern(Sym*, Node*, long, long); -void gextern(Sym*, Node*, long, long); void outcode(void); void ieeedtod(Ieee*, double); @@ -302,12 +334,12 @@ void addmove(Reg*, int, int, int); Bits mkvar(Adr*, int); void prop(Reg*, Bits, Bits); -void loopit(Reg*, long); +void loopit(Reg*, int32); void synch(Reg*, Bits); -ulong allreg(ulong, Rgn*); +uint32 allreg(uint32, Rgn*); void paint1(Reg*, int); -ulong paint2(Reg*, int); -void paint3(Reg*, int, long, int); +uint32 paint2(Reg*, int); +void paint3(Reg*, int, int32, int); void addreg(Adr*, int); /* @@ -333,15 +365,15 @@ int copysub(Adr*, Adr*, Adr*, int); int copysub1(Prog*, Adr*, Adr*, int); -long RtoB(int); -long FtoB(int); -int BtoR(long); -int BtoF(long); +int32 RtoB(int); +int32 FtoB(int); +int BtoR(int32); +int BtoF(int32); -void predicate(void); -int isbranch(Prog *); -int predicable(Prog *p); -int modifiescpsr(Prog *p); +void predicate(void); +int isbranch(Prog *); +int predicable(Prog *p); +int modifiescpsr(Prog *p); #pragma varargck type "A" int #pragma varargck type "B" Bits diff -r d8d00747375b sys/src/cmd/5c/list.c --- a/sys/src/cmd/5c/list.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/5c/list.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,3 +1,34 @@ +// Inferno utils/5c/list.c +// http://code.google.com/p/inferno-os/source/browse/utils/5c/list.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. + + #define EXTERN #include "gc.h" @@ -28,7 +59,7 @@ if(str[0]) strcat(str, " "); if(var[i].sym == S) { - sprint(ss, "$%ld", var[i].offset); + sprint(ss, "$%d", var[i].offset); s = ss; } else s = var[i].sym->name; @@ -41,9 +72,9 @@ } char *extra [] = { - ".EQ", ".NE", ".CS", ".CC", - ".MI", ".PL", ".VS", ".VC", - ".HI", ".LS", ".GE", ".LT", + ".EQ", ".NE", ".CS", ".CC", + ".MI", ".PL", ".VS", ".VC", + ".HI", ".LS", ".GE", ".LT", ".GT", ".LE", "", ".NV", }; @@ -56,7 +87,7 @@ p = va_arg(fp->args, Prog*); a = p->as; - s = p->scond; + s = p->scond; strcpy(sc, extra[s & C_SCOND]); if(s & C_SBIT) strcat(sc, ".S"); @@ -132,6 +163,10 @@ sprint(str, "$%N", a); break; + case D_CONST2: + sprint(str, "$%d-%d", a->offset, a->offset2); + break; + case D_SHIFT: v = a->offset; op = "<<>>->@>" + (((v>>5) & 3) << 1); @@ -169,7 +204,7 @@ break; case D_BRANCH: - sprint(str, "%ld(PC)", a->offset-pc); + sprint(str, "%d(PC)", a->offset-pc); break; case D_FCONST: @@ -194,6 +229,7 @@ sprint(str, "GOK-reglist"); switch(a->type) { case D_CONST: + case D_CONST2: if(a->reg != NREG) break; if(a->sym != S) @@ -271,7 +307,7 @@ a = va_arg(fp->args, Adr*); s = a->sym; if(s == S) { - sprint(str, "%ld", a->offset); + sprint(str, "%d", a->offset); goto out; } switch(a->name) { @@ -280,23 +316,23 @@ break; case D_NONE: - sprint(str, "%ld", a->offset); + sprint(str, "%d", a->offset); break; case D_EXTERN: - sprint(str, "%s+%ld(SB)", s->name, a->offset); + sprint(str, "%s+%d(SB)", s->name, a->offset); break; case D_STATIC: - sprint(str, "%s<>+%ld(SB)", s->name, a->offset); + sprint(str, "%s<>+%d(SB)", s->name, a->offset); break; case D_AUTO: - sprint(str, "%s-%ld(SP)", s->name, -a->offset); + sprint(str, "%s-%d(SP)", s->name, -a->offset); break; case D_PARAM: - sprint(str, "%s+%ld(FP)", s->name, a->offset); + sprint(str, "%s+%d(FP)", s->name, a->offset); break; } out: diff -r d8d00747375b sys/src/cmd/5c/mkenam --- a/sys/src/cmd/5c/mkenam Thu Sep 29 03:00:00 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -ed - ../5c/5.out.h <<'!' -v/^ A/d -,s/^ A/ "/ -g/ .*$/s/// -,s/,*$/",/ -1i -char* anames[] = -{ -. -$a -}; -. -w enam.c -Q -! diff -r d8d00747375b sys/src/cmd/5c/mkfile --- a/sys/src/cmd/5c/mkfile Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/5c/mkfile Mon Nov 14 17:35:25 2011 +0100 @@ -16,7 +16,7 @@ HFILES=\ gc.h\ - 5.out.h\ + ../5l/5.out.h\ ../cc/cc.h\ LIB=../cc/cc.a$O @@ -36,3 +36,9 @@ $O.out -S t $LD -o t.out t.$O t.out + +CLEANFILES=enam.c + +enam.c: ../5l/5.out.h + ape/psh ../5l/mkenam + diff -r d8d00747375b sys/src/cmd/5c/mul.c --- a/sys/src/cmd/5c/mul.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/5c/mul.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,3 +1,34 @@ +// Inferno utils/5c/mul.c +// http://code.google.com/p/inferno-os/source/browse/utils/5c/mul.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 "gc.h" /* @@ -12,15 +43,15 @@ static int maxmulops = 3; /* max # of ops to replace mul with */ static int multabp; -static long mulval; +static int32 mulval; static char* mulcp; -static long valmax; +static int32 valmax; static int shmax; static int docode(char *hp, char *cp, int r0, int r1); static int gen1(int len); -static int gen2(int len, long r1); -static int gen3(int len, long r0, long r1, int flag); +static int gen2(int len, int32 r1); +static int gen3(int len, int32 r0, int32 r1, int flag); enum { SR1 = 1<<0, /* r1 has been shifted */ @@ -30,7 +61,7 @@ }; Multab* -mulcon0(long v) +mulcon0(int32 v) { int a1, a2, g; Multab *m, *m1; @@ -84,7 +115,7 @@ if(docode(hintab[g].hint, m->code, 1, 0)) return m; - print("multiply table failure %ld\n", v); + print("multiply table failure %d\n", v); m->code[0] = 0; return 0; @@ -101,7 +132,7 @@ if(gen1(g)) { if(docode(hint, m->code, 1, 0)) return m; - print("multiply table failure %ld\n", v); + print("multiply table failure %d\n", v); break; } } @@ -235,7 +266,7 @@ } static int -gen2(int len, long r1) +gen2(int len, int32 r1) { int i; @@ -285,10 +316,10 @@ } static int -gen3(int len, long r0, long r1, int flag) +gen3(int len, int32 r0, int32 r1, int flag) { int i, f1, f2; - long x; + int32 x; if(r0 <= 0 || r0 >= r1 || diff -r d8d00747375b sys/src/cmd/5c/peep.c --- a/sys/src/cmd/5c/peep.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/5c/peep.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,3 +1,34 @@ +// Inferno utils/5c/peep.c +// http://code.google.com/p/inferno-os/source/browse/utils/5c/peep.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 "gc.h" int xtramodes(Reg*, Adr*); @@ -806,7 +837,7 @@ if(p1->from.type == D_REG || (p1->from.type == D_SHIFT && (p1->from.offset&(1<<4)) == 0 && (p->as != AMOVB || (a == &p->from && (p1->from.offset&~0xf) == 0))) || - (p1->from.type == D_CONST && + (p1->from.type == D_CONST && p1->from.offset > -4096 && p1->from.offset < 4096)) if(nochange(uniqs(r1), r, p1)) { if(a != &p->from || v.reg != p->to.reg) @@ -814,7 +845,7 @@ if(p1->reg == NREG || p1->reg == v.reg) /* pre-indexing */ p->scond |= C_WBIT; - else return 0; + else return 0; } switch (p1->from.type) { case D_REG: @@ -884,7 +915,7 @@ default: if(debug['P']) - print(" (???)"); + print(" (?)"); return 2; case AMOVM: @@ -924,7 +955,7 @@ return 3; } return 0; - + case ANOP: /* read, write */ case AMOVW: case AMOVF: @@ -1069,7 +1100,7 @@ if(v->type == D_REG) { if(v->reg <= REGEXT && v->reg > exregoffset) return 2; - if(v->reg == REGARG) + if(v->reg == (uchar)REGARG) return 2; } if(v->type == D_FREG) @@ -1087,7 +1118,7 @@ case ATEXT: /* funny */ if(v->type == D_REG) - if(v->reg == REGARG) + if(v->reg == (uchar)REGARG) return 3; return 0; } @@ -1228,26 +1259,26 @@ struct { int opcode; int notopcode; - int scond; - int notscond; -} predinfo[] = { - { ABEQ, ABNE, 0x0, 0x1, }, - { ABNE, ABEQ, 0x1, 0x0, }, - { ABCS, ABCC, 0x2, 0x3, }, - { ABHS, ABLO, 0x2, 0x3, }, - { ABCC, ABCS, 0x3, 0x2, }, - { ABLO, ABHS, 0x3, 0x2, }, - { ABMI, ABPL, 0x4, 0x5, }, - { ABPL, ABMI, 0x5, 0x4, }, - { ABVS, ABVC, 0x6, 0x7, }, - { ABVC, ABVS, 0x7, 0x6, }, - { ABHI, ABLS, 0x8, 0x9, }, - { ABLS, ABHI, 0x9, 0x8, }, - { ABGE, ABLT, 0xA, 0xB, }, - { ABLT, ABGE, 0xB, 0xA, }, - { ABGT, ABLE, 0xC, 0xD, }, - { ABLE, ABGT, 0xD, 0xC, }, -}; + int scond; + int notscond; +} predinfo[] = { + { ABEQ, ABNE, 0x0, 0x1, }, + { ABNE, ABEQ, 0x1, 0x0, }, + { ABCS, ABCC, 0x2, 0x3, }, + { ABHS, ABLO, 0x2, 0x3, }, + { ABCC, ABCS, 0x3, 0x2, }, + { ABLO, ABHS, 0x3, 0x2, }, + { ABMI, ABPL, 0x4, 0x5, }, + { ABPL, ABMI, 0x5, 0x4, }, + { ABVS, ABVC, 0x6, 0x7, }, + { ABVC, ABVS, 0x7, 0x6, }, + { ABHI, ABLS, 0x8, 0x9, }, + { ABLS, ABHI, 0x9, 0x8, }, + { ABGE, ABLT, 0xA, 0xB, }, + { ABLT, ABGE, 0xB, 0xA, }, + { ABGT, ABLE, 0xC, 0xD, }, + { ABLE, ABGT, 0xD, 0xC, }, +}; typedef struct { Reg *start; @@ -1264,7 +1295,7 @@ Setcond, Toolong }; - + enum { Falsecond, Truecond, @@ -1272,10 +1303,10 @@ Keepbranch }; -int +int isbranch(Prog *p) { - return (ABEQ <= p->as) && (p->as <= ABLE); + return (ABEQ <= p->as) && (p->as <= ABLE); } int @@ -1292,27 +1323,25 @@ || p->as == ASIGNAME || p->as == ATEXT || p->as == AWORD - || p->as == ADYNT - || p->as == AINIT || p->as == ABCASE || p->as == ACASE) - return 0; - return 1; + return 0; + return 1; } -/* - * Depends on an analysis of the encodings performed by 5l. +/* + * Depends on an analysis of the encodings performed by 5l. * These seem to be all of the opcodes that lead to the "S" bit - * being set in the instruction encodings. - * + * being set in the instruction encodings. + * * C_SBIT may also have been set explicitly in p->scond. - */ + */ int modifiescpsr(Prog *p) { return (p->scond&C_SBIT) - || p->as == ATST - || p->as == ATEQ + || p->as == ATST + || p->as == ATEQ || p->as == ACMN || p->as == ACMP || p->as == AMULU @@ -1322,7 +1351,7 @@ || p->as == AMOD || p->as == AMODU || p->as == ABL; -} +} /* * Find the maximal chain of instructions starting with r which could @@ -1368,24 +1397,24 @@ successor(Reg *r) { if (r->s1) - return r->s1; + return r->s1; else - return r->s2; + return r->s2; } void applypred(Reg *rstart, Joininfo *j, int cond, int branch) { - int pred; - Reg *r; + int pred; + Reg *r; if(j->len == 0) return; if (cond == Truecond) pred = predinfo[rstart->prog->as - ABEQ].scond; else - pred = predinfo[rstart->prog->as - ABEQ].notscond; - + pred = predinfo[rstart->prog->as - ABEQ].notscond; + for (r = j->start; ; r = successor(r)) { if (r->prog->as == AB) { if (r != j->last || branch == Delbranch) @@ -1397,7 +1426,7 @@ r->prog->as = predinfo[rstart->prog->as - ABEQ].notopcode; } } - else if (predicable(r->prog)) + else if (predicable(r->prog)) r->prog->scond = (r->prog->scond&~C_SCOND)|pred; if (r->s1 != r->link) { r->s1 = r->link; @@ -1410,7 +1439,7 @@ void predicate(void) -{ +{ Reg *r; int t1, t2; Joininfo j1, j2; @@ -1434,6 +1463,6 @@ excise(r); continue; } - } - } + } + } } diff -r d8d00747375b sys/src/cmd/5c/reg.c --- a/sys/src/cmd/5c/reg.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/5c/reg.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,3 +1,34 @@ +// Inferno utils/5c/reg.c +// http://code.google.com/p/inferno-os/source/browse/utils/5c/reg.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 "gc.h" void addsplits(void); @@ -35,16 +66,22 @@ void regopt(Prog *p) { + USED(p); + // TODO(kaib): optimizer disabled because it smashes R8 when running out of registers + // the disable is unconventionally here because the call is in common code shared by 5c/6c/8c + return; + +#ifdef NOTDEF Reg *r, *r1, *r2; Prog *p1; int i, z; - long initpc, val, npc; - ulong vreg; + int32 initpc, val, npc; + uint32 vreg; Bits bit; struct { - long m; - long c; + int32 m; + int32 c; Reg* p; } log5[6], *lp; @@ -274,7 +311,7 @@ if(debug['R'] && debug['v']) { print("\nprop structure:\n"); for(r = firstr; r != R; r = r->link) { - print("%ld:%P", r->loop, r->prog); + print("%d:%P", r->loop, r->prog); for(z=0; zset.b[z] | r->refahead.b[z] | r->calahead.b[z] | @@ -455,6 +492,7 @@ r1->link = freer; freer = firstr; } +#endif } void @@ -553,7 +591,7 @@ { Var *v; int i, t, n, et, z; - long o; + int32 o; Bits bit; Sym *s; @@ -703,8 +741,8 @@ * such a node is a loop head. * recursively, all preds with a greater rpo number are in the loop */ -long -postorder(Reg *r, Reg **rpo2r, long n) +int32 +postorder(Reg *r, Reg **rpo2r, int32 n) { Reg *r1; @@ -720,10 +758,10 @@ return n; } -long -rpolca(long *idom, long rpo1, long rpo2) +int32 +rpolca(int32 *idom, int32 rpo1, int32 rpo2) { - long t; + int32 t; if(rpo1 == -1) return rpo2; @@ -744,7 +782,7 @@ } int -doms(long *idom, long r, long s) +doms(int32 *idom, int32 r, int32 s) { while(s > r) s = idom[s]; @@ -752,9 +790,9 @@ } int -loophead(long *idom, Reg *r) +loophead(int32 *idom, Reg *r) { - long src; + int32 src; src = r->rpo; if(r->p1 != R && doms(idom, src, r->p1->rpo)) @@ -766,7 +804,7 @@ } void -loopmark(Reg **rpo2r, long head, Reg *r) +loopmark(Reg **rpo2r, int32 head, Reg *r) { if(r->rpo < head || r->active == head) return; @@ -779,17 +817,16 @@ } void -loopit(Reg *r, long nr) +loopit(Reg *r, int32 nr) { Reg *r1; - long i, d, me; + int32 i, d, me; if(nr > maxnr) { rpo2r = alloc(nr * sizeof(Reg*)); - idom = alloc(nr * sizeof(long)); + idom = alloc(nr * sizeof(int32)); maxnr = nr; } - d = postorder(r, rpo2r, 0); if(d > nr) fatal(Z, "too many reg nodes"); @@ -849,8 +886,8 @@ } } -ulong -allreg(ulong b, Rgn *r) +uint32 +allreg(uint32 b, Rgn *r) { Var *v; int i; @@ -899,7 +936,7 @@ Reg *r1; Prog *p; int z; - ulong bb; + uint32 bb; z = bn/32; bb = 1L<<(bn%32); @@ -921,7 +958,7 @@ if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb) { change -= CLOAD * r->loop; if(debug['R'] && debug['v']) - print("%ld%P\tld %B $%d\n", r->loop, + print("%d%P\td %B $%d\n", r->loop, r->prog, blsh(bn), change); } for(;;) { @@ -931,21 +968,21 @@ if(r->use1.b[z] & bb) { change += CREF * r->loop; if(debug['R'] && debug['v']) - print("%ld%P\tu1 %B $%d\n", r->loop, + print("%d%P\tu1 %B $%d\n", r->loop, p, blsh(bn), change); } if((r->use2.b[z]|r->set.b[z]) & bb) { change += CREF * r->loop; if(debug['R'] && debug['v']) - print("%ld%P\tu2 %B $%d\n", r->loop, + print("%d%P\tu2 %B $%d\n", r->loop, p, blsh(bn), change); } if(STORE(r) & r->regdiff.b[z] & bb) { change -= CLOAD * r->loop; if(debug['R'] && debug['v']) - print("%ld%P\tst %B $%d\n", r->loop, + print("%d%P\tst %B $%d\n", r->loop, p, blsh(bn), change); } @@ -970,12 +1007,12 @@ } } -ulong +uint32 paint2(Reg *r, int bn) { Reg *r1; int z; - ulong bb, vreg; + uint32 bb, vreg; z = bn/32; bb = 1L << (bn%32); @@ -1022,12 +1059,12 @@ } void -paint3(Reg *r, int bn, long rb, int rn) +paint3(Reg *r, int bn, int32 rb, int rn) { Reg *r1; Prog *p; int z; - ulong bb; + uint32 bb; z = bn/32; bb = 1L << (bn%32); @@ -1113,19 +1150,19 @@ * ... ... * 10 R10 */ -long +int32 RtoB(int r) { - if(r >= REGMIN && r <= REGMAX) - return 1L << r; - return 0; + if(r < 2 || r >= REGTMP-2) // excluded R9 and R10 for m and g + return 0; + return 1L << r; } int -BtoR(long b) +BtoR(int32 b) { - b &= 0x01fcL; + b &= 0x01fcL; // excluded R9 and R10 for m and g if(b == 0) return 0; return bitno(b); @@ -1138,7 +1175,7 @@ * ... ... * 23 F7 */ -long +int32 FtoB(int f) { @@ -1148,7 +1185,7 @@ } int -BtoF(long b) +BtoF(int32 b) { b &= 0xfc0000L; diff -r d8d00747375b sys/src/cmd/5c/sgen.c --- a/sys/src/cmd/5c/sgen.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/5c/sgen.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,5 +1,53 @@ +// Inferno utils/5c/sgen.c +// http://code.google.com/p/inferno-os/source/browse/utils/5c/sgen.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 "gc.h" +Prog* +gtext(Sym *s, int32 stkoff) +{ + int32 a; + + a = 0; + if(!(textflag & NOSPLIT)) + a = argsize(); + else if(stkoff >= 128) + yyerror("stack frame too large for NOSPLIT function"); + + gpseudo(ATEXT, s, nodconst(stkoff)); + p->to.type = D_CONST2; + p->to.offset2 = a; + return p; +} + void noretval(int n) { diff -r d8d00747375b sys/src/cmd/5c/swt.c --- a/sys/src/cmd/5c/swt.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/5c/swt.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,21 +1,42 @@ +// Inferno utils/5c/swt.c +// http://code.google.com/p/inferno-os/source/browse/utils/5c/swt.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 "gc.h" void -swit1(C1 *q, int nc, long def, Node *n) -{ - Node tn; - - regalloc(&tn, ®node, Z); - swit2(q, nc, def, n, &tn); - regfree(&tn); -} - -void -swit2(C1 *q, int nc, long def, Node *n, Node *tn) +swit1(C1 *q, int nc, int32 def, Node *n) { C1 *r; int i; - long v; + int32 v; Prog *sp; if(nc >= 3) { @@ -26,7 +47,7 @@ if(nc < 5) { for(i=0; ival); + print("case = %.8ux\n", q->val); gopcode(OEQ, nodconst(q->val), n, Z); patch(p, q->label); q++; @@ -39,17 +60,17 @@ i = nc / 2; r = q+i; if(debug['W']) - print("case > %.8lux\n", r->val); + print("case > %.8ux\n", r->val); gopcode(OGT, nodconst(r->val), n, Z); sp = p; gopcode(OEQ, nodconst(r->val), n, Z); /* just gen the B.EQ */ patch(p, r->label); - swit2(q, i, def, n, tn); + swit1(q, i, def, n); if(debug['W']) - print("case < %.8lux\n", r->val); + print("case < %.8ux\n", r->val); patch(sp, pc); - swit2(r+1, nc-i-1, def, n, tn); + swit1(r+1, nc-i-1, def, n); return; direct: @@ -60,7 +81,7 @@ patch(p, def); for(i=0; ival); + print("case = %.8ux\n", q->val); while(q->val != v) { nextpc(); p->as = ABCASE; @@ -81,7 +102,7 @@ bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn) { int sh; - long v; + int32 v; Node *l; /* @@ -119,7 +140,7 @@ void bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn) { - long v; + int32 v; Node nod, *l; int sh; @@ -149,10 +170,10 @@ regfree(n3); } -long -outstring(char *s, long n) +int32 +outstring(char *s, int32 n) { - long r; + int32 r; if(suppress) return nstring; @@ -179,7 +200,7 @@ { Node *l, *r, nod1, nod2; Multab *m; - long v, vs; + int32 v, vs; int o; char code[sizeof(m->code)+2], *p; @@ -206,7 +227,7 @@ return 0; } if(debug['M'] && debug['v']) - print("%L multiply: %ld\n", n->lineno, v); + print("%L multiply: %d\n", n->lineno, v); memmove(code, m->code, sizeof(m->code)); code[sizeof(m->code)] = 0; @@ -226,7 +247,7 @@ if(vs < 0) { gopcode(OAS, &nod1, Z, &nod1); gopcode(OSUB, &nod1, nodconst(0), nn); - } else + } else gopcode(OAS, &nod1, Z, nn); regfree(&nod1); return 1; @@ -269,9 +290,9 @@ } void -sextern(Sym *s, Node *a, long o, long w) +sextern(Sym *s, Node *a, int32 o, int32 w) { - long e, lw; + int32 e, lw; for(e=0; eop == OCONST && typev[a->type->etype]) { - if(align(0, types[TCHAR], Aarg1)) /* isbigendian */ + if(isbigendian) gpseudo(ADATA, s, nod32const(a->vconst>>32)); else gpseudo(ADATA, s, nod32const(a->vconst)); p->from.offset += o; p->reg = 4; - if(align(0, types[TCHAR], Aarg1)) /* isbigendian */ + if(isbigendian) gpseudo(ADATA, s, nod32const(a->vconst)); else gpseudo(ADATA, s, nod32const(a->vconst>>32)); @@ -351,6 +372,24 @@ pc++; } } + + Bprint(&outbuf, "go object %s %s %s\n", getgoos(), thestring, getgoversion()); + if(ndynimp > 0 || ndynexp > 0) { + int i; + + Bprint(&outbuf, "\n"); + Bprint(&outbuf, "$$ // exports\n\n"); + Bprint(&outbuf, "$$ // local types\n\n"); + Bprint(&outbuf, "$$ // dynimport\n"); + for(i=0; ilink) { p = h->name; op = 0; - /* on windows skip drive specifier in pathname */ if(systemtype(Windows) && p && p[1] == ':'){ - p += 2; - c = *p; - } - if(p && p[0] != c && h->offset == 0 && pathname){ - /* on windows skip drive specifier in pathname */ + c = p[2]; + } else if(p && p[0] != c && h->offset == 0 && pathname){ if(systemtype(Windows) && pathname[1] == ':') { op = p; - p = pathname+2; - c = *p; + p = pathname; + c = p[2]; } else if(pathname[0] == c){ op = p; p = pathname; @@ -478,7 +513,7 @@ zname(Biobuf *b, Sym *s, int t) { char *n, bf[7]; - ulong sig; + uint32 sig; n = s->name; if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){ @@ -505,7 +540,7 @@ char* zaddr(char *bp, Adr *a, int s) { - long l; + int32 l; Ieee e; bp[0] = a->type; @@ -523,6 +558,13 @@ case D_PSR: break; + case D_CONST2: + l = a->offset2; + bp[0] = l; + bp[1] = l>>8; + bp[2] = l>>16; + bp[3] = l>>24; + bp += 4; // fall through case D_OREG: case D_CONST: case D_BRANCH: @@ -559,10 +601,10 @@ return bp; } -long -align(long i, Type *t, int op) +int32 +align(int32 i, Type *t, int op, int32 *maxalign) { - long o; + int32 o; Type *v; int w; @@ -574,18 +616,26 @@ break; case Asu2: /* padding at end of a struct */ - w = SZ_LONG; + w = *maxalign; + if(w < 1) + w = 1; if(packflg) w = packflg; break; - case Ael1: /* initial allign of struct element */ + case Ael1: /* initial align of struct element */ for(v=t; v->etype==TARRAY; v=v->link) ; - w = ewidth[v->etype]; - if(w <= 0 || w >= SZ_LONG) - w = SZ_LONG; - if(packflg) + if(v->etype == TSTRUCT || v->etype == TUNION) + w = v->align; + else { + w = ewidth[v->etype]; + if(w == 8) + w = 4; + } + if(w < 1 || w > SZ_LONG) + fatal(Z, "align"); + if(packflg) w = packflg; break; @@ -595,12 +645,12 @@ case Aarg0: /* initial passbyptr argument in arg list */ if(typesuv[t->etype]) { - o = align(o, types[TIND], Aarg1); - o = align(o, types[TIND], Aarg2); + o = align(o, types[TIND], Aarg1, nil); + o = align(o, types[TIND], Aarg2, nil); } break; - case Aarg1: /* initial allign of parameter */ + case Aarg1: /* initial align of parameter */ w = ewidth[t->etype]; if(w <= 0 || w >= SZ_LONG) { w = SZ_LONG; @@ -611,25 +661,29 @@ case Aarg2: /* width of a parameter */ o += t->width; - w = SZ_LONG; + w = t->width; + if(w > SZ_LONG) + w = SZ_LONG; break; - case Aaut3: /* total allign of automatic */ - o = align(o, t, Ael2); - o = align(o, t, Ael1); + case Aaut3: /* total align of automatic */ + o = align(o, t, Ael2, nil); + o = align(o, t, Ael1, nil); w = SZ_LONG; /* because of a pun in cc/dcl.c:contig() */ break; } - o = round(o, w); + o = xround(o, w); + if(maxalign != nil && *maxalign < w) + *maxalign = w; if(debug['A']) - print("align %s %ld %T = %ld\n", bnames[op], i, t, o); + print("align %s %d %T = %d\n", bnames[op], i, t, o); return o; } -long -maxround(long max, long v) +int32 +maxround(int32 max, int32 v) { - v = round(v, SZ_LONG); + v = xround(v, SZ_LONG); if(v > max) return v; return max; diff -r d8d00747375b sys/src/cmd/5c/txt.c --- a/sys/src/cmd/5c/txt.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/5c/txt.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,7 +1,36 @@ +// Inferno utils/5c/txt.c +// http://code.google.com/p/inferno-os/source/browse/utils/5c/txt.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 "gc.h" -static char resvreg[nelem(reg)]; - void ginit(void) { @@ -30,7 +59,7 @@ zprog.from.name = D_NONE; zprog.from.reg = NREG; zprog.to = zprog.from; - zprog.scond = 0xE; + zprog.scond = 0xE; regnode.op = OREGISTER; regnode.class = CEXREG; @@ -82,16 +111,6 @@ com64init(); memset(reg, 0, sizeof(reg)); - /* don't allocate */ - reg[REGTMP] = 1; - reg[REGSB] = 1; - reg[REGSP] = 1; - reg[REGLINK] = 1; - reg[REGPC] = 1; - /* keep two external registers */ - reg[REGEXT] = 1; - reg[REGEXT-1] = 1; - memmove(resvreg, reg, sizeof(reg)); } void @@ -101,10 +120,10 @@ Sym *s; for(i=0; itype->etype) { case TCHAR: @@ -291,16 +309,9 @@ if(i >= 0 && i < NREG) goto out; } - j = lasti + REGRET+1; - for(i=REGRET+1; i= NREG) - j = REGRET+1; - if(reg[j] == 0 && resvreg[j] == 0) { - i = j; + for(i=REGRET+1; i<=REGEXT-2; i++) + if(reg[i] == 0) goto out; - } - j++; - } diag(tn, "out of fixed registers"); goto err; @@ -312,16 +323,9 @@ if(i >= NREG && i < NREG+NFREG) goto out; } - j = 0*2 + NREG; - for(i=NREG; i= NREG+NFREG) - j = NREG; - if(reg[j] == 0) { - i = j; + for(i=NREG; i= 5) - lasti = 0; nodreg(n, tn, i); } @@ -369,7 +370,7 @@ void regsalloc(Node *n, Node *nn) { - cursafe = align(cursafe, nn->type, Aaut3); + cursafe = align(cursafe, nn->type, Aaut3, nil); maxargsafe = maxround(maxargsafe, cursafe+curarg); *n = *nodsafe; n->xoffset = -(stkoff + cursafe); @@ -381,24 +382,28 @@ void regaalloc1(Node *n, Node *nn) { + if(REGARG < 0) { + fatal(n, "regaalloc1 and REGARG<0"); + return; + } nodreg(n, nn, REGARG); reg[REGARG]++; - curarg = align(curarg, nn->type, Aarg1); - curarg = align(curarg, nn->type, Aarg2); + curarg = align(curarg, nn->type, Aarg1, nil); + curarg = align(curarg, nn->type, Aarg2, nil); maxargsafe = maxround(maxargsafe, cursafe+curarg); } void regaalloc(Node *n, Node *nn) { - curarg = align(curarg, nn->type, Aarg1); + curarg = align(curarg, nn->type, Aarg1, nil); *n = *nn; n->op = OINDREG; n->reg = REGSP; n->xoffset = curarg + SZ_LONG; n->complex = 0; n->addable = 20; - curarg = align(curarg, nn->type, Aarg2); + curarg = align(curarg, nn->type, Aarg2, nil); maxargsafe = maxround(maxargsafe, cursafe+curarg); } @@ -437,7 +442,7 @@ void naddr(Node *n, Adr *a) { - long v; + int32 v; a->type = D_NONE; if(n == Z) @@ -728,7 +733,7 @@ return; } // fall through - + case TINT: case TLONG: case TIND: @@ -1120,6 +1125,7 @@ print("%P\n", p); } +int samaddr(Node *f, Node *t) { @@ -1158,7 +1164,7 @@ } void -patch(Prog *op, long pc) +patch(Prog *op, int32 pc) { op->to.offset = pc; @@ -1174,8 +1180,10 @@ p->from.type = D_OREG; p->from.sym = s; p->from.name = D_EXTERN; - if(a == ATEXT) - p->reg = (profileflg ? 0 : NOPROF); + if(a == ATEXT) { + p->reg = textflag; + textflag = 0; + } if(s->class == CSTATIC) p->from.name = D_STATIC; naddr(n, &p->to); @@ -1205,7 +1213,7 @@ } int -sval(long v) +sval(int32 v) { int i; @@ -1214,23 +1222,20 @@ return 1; if((~v & ~0xff) == 0) return 1; - v = (v<<2) | ((ulong)v>>30); + v = (v<<2) | ((uint32)v>>30); } return 0; } -long +int32 exreg(Type *t) { - long o; + int32 o; if(typechlp[t->etype]) { - if(exregoffset <= REGEXT-2) + if(exregoffset <= REGEXT-4) return 0; o = exregoffset; - if(reg[o] && !resvreg[o]) - return 0; - resvreg[o] = reg[o] = 1; exregoffset--; return o; } @@ -1238,9 +1243,6 @@ if(exfregoffset <= NFREG-1) return 0; o = exfregoffset + NREG; - if(reg[o] && !resvreg[o]) - return 0; - resvreg[o] = reg[o] = 1; exfregoffset--; return o; } @@ -1271,7 +1273,7 @@ SZ_INT, /* [TENUM] */ }; -long ncast[NTYPE] = +int32 ncast[NTYPE] = { 0, /* [TXXX] */ BCHAR|BUCHAR, /* [TCHAR] */ diff -r d8d00747375b sys/src/cmd/5l/5.out.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/src/cmd/5l/5.out.h Mon Nov 14 17:35:25 2011 +0100 @@ -0,0 +1,270 @@ +// Inferno utils/5c/5.out.h +// http://code.google.com/p/inferno-os/source/browse/utils/5c/5.out.h +// +// 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. + +#define NSNAME 8 +#define NSYM 50 +#define NREG 16 + +#define NOPROF (1<<0) +#define DUPOK (1<<1) +#define NOSPLIT (1<<2) +#define ALLTHUMBS (1<<3) + +#define REGRET 0 +/* -1 disables use of REGARG */ +#define REGARG -1 +/* compiler allocates R1 up as temps */ +/* compiler allocates register variables R3 up */ +#define REGEXT 10 +/* these two registers are declared in runtime.h */ +#define REGG (REGEXT-0) +#define REGM (REGEXT-1) +/* compiler allocates external registers R10 down */ +#define REGTMP 11 +#define REGSB 12 +#define REGSP 13 +#define REGLINK 14 +#define REGPC 15 + +#define NFREG 8 +#define FREGRET 0 +#define FREGEXT 7 +#define FREGTMP 15 +/* compiler allocates register variables F0 up */ +/* compiler allocates external registers F7 down */ + +enum as +{ + AXXX, + + AAND, + AEOR, + ASUB, + ARSB, + AADD, + AADC, + ASBC, + ARSC, + ATST, + ATEQ, + ACMP, + ACMN, + AORR, + ABIC, + + AMVN, + + AB, + ABL, + +/* + * Do not reorder or fragment the conditional branch + * opcodes, or the predication code will break + */ + ABEQ, + ABNE, + ABCS, + ABHS, + ABCC, + ABLO, + ABMI, + ABPL, + ABVS, + ABVC, + ABHI, + ABLS, + ABGE, + ABLT, + ABGT, + ABLE, + + AMOVWD, + AMOVWF, + AMOVDW, + AMOVFW, + AMOVFD, + AMOVDF, + AMOVF, + AMOVD, + + ACMPF, + ACMPD, + AADDF, + AADDD, + ASUBF, + ASUBD, + AMULF, + AMULD, + ADIVF, + ADIVD, + ASQRTF, + ASQRTD, + + ASRL, + ASRA, + ASLL, + AMULU, + ADIVU, + AMUL, + ADIV, + AMOD, + AMODU, + + AMOVB, + AMOVBU, + AMOVH, + AMOVHU, + AMOVW, + AMOVM, + ASWPBU, + ASWPW, + + ANOP, + ARFE, + ASWI, + AMULA, + + ADATA, + AGLOBL, + AGOK, + AHISTORY, + ANAME, + ARET, + ATEXT, + AWORD, + ADYNT_, + AINIT_, + ABCASE, + ACASE, + + AEND, + + AMULL, + AMULAL, + AMULLU, + AMULALU, + + ABX, + ABXRET, + ADWORD, + + ASIGNAME, + + ALDREX, + ASTREX, + + ALDREXD, + ASTREXD, + + ALAST, +}; + +/* scond byte */ +#define C_SCOND ((1<<4)-1) +#define C_SBIT (1<<4) +#define C_PBIT (1<<5) +#define C_WBIT (1<<6) +#define C_FBIT (1<<7) /* psr flags-only */ +#define C_UBIT (1<<7) /* up bit, unsigned bit */ + +#define C_SCOND_EQ 0 +#define C_SCOND_NE 1 +#define C_SCOND_HS 2 +#define C_SCOND_LO 3 +#define C_SCOND_MI 4 +#define C_SCOND_PL 5 +#define C_SCOND_VS 6 +#define C_SCOND_VC 7 +#define C_SCOND_HI 8 +#define C_SCOND_LS 9 +#define C_SCOND_GE 10 +#define C_SCOND_LT 11 +#define C_SCOND_GT 12 +#define C_SCOND_LE 13 +#define C_SCOND_NONE 14 +#define C_SCOND_NV 15 + +/* D_SHIFT type */ +#define SHIFT_LL 0<<5 +#define SHIFT_LR 1<<5 +#define SHIFT_AR 2<<5 +#define SHIFT_RR 3<<5 + +/* type/name */ +#define D_GOK 0 +#define D_NONE 1 + +/* type */ +#define D_BRANCH (D_NONE+1) +#define D_OREG (D_NONE+2) +#define D_CONST (D_NONE+7) +#define D_FCONST (D_NONE+8) +#define D_SCONST (D_NONE+9) +#define D_PSR (D_NONE+10) +#define D_REG (D_NONE+12) +#define D_FREG (D_NONE+13) +#define D_FILE (D_NONE+16) +#define D_OCONST (D_NONE+17) +#define D_FILE1 (D_NONE+18) + +#define D_SHIFT (D_NONE+19) +#define D_FPCR (D_NONE+20) +#define D_REGREG (D_NONE+21) +#define D_ADDR (D_NONE+22) + +#define D_SBIG (D_NONE+23) +#define D_CONST2 (D_NONE+24) + +/* name */ +#define D_EXTERN (D_NONE+3) +#define D_STATIC (D_NONE+4) +#define D_AUTO (D_NONE+5) +#define D_PARAM (D_NONE+6) + +/* internal only */ +#define D_SIZE (D_NONE+40) +#define D_PCREL (D_NONE+41) + +/* + * this is the ranlib header + */ +#define SYMDEF "__.SYMDEF" + +/* + * this is the simulated IEEE floating point + */ +typedef struct ieee Ieee; +struct ieee +{ + int32 l; /* contains ls-man 0xffffffff */ + int32 h; /* contains sign 0x80000000 + exp 0x7ff00000 + ms-man 0x000fffff */ +}; diff -r d8d00747375b sys/src/cmd/5l/asm.c --- a/sys/src/cmd/5l/asm.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/5l/asm.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,10 +1,44 @@ +// Inferno utils/5l/asm.c +// http://code.google.com/p/inferno-os/source/browse/utils/5l/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. + +// Writing object files. + #include "l.h" - -long OFFSET; +#include "../ld/lib.h" +#include "../ld/elf.h" static Prog *PP; -long +char linuxdynld[] = "/lib/ld-linux.so.2"; + +int32 entryvalue(void) { char *a; @@ -16,139 +50,349 @@ s = lookup(a, 0); if(s->type == 0) return INITTEXT; - switch(s->type) { - case STEXT: - case SLEAF: - break; - case SDATA: - if(dlm) - return s->value+INITDAT; - default: + if(s->type != STEXT) diag("entry not text: %s", s->name); + return s->value; +} + +enum { + ElfStrEmpty, + ElfStrInterp, + ElfStrHash, + ElfStrGot, + ElfStrGotPlt, + ElfStrDynamic, + ElfStrDynsym, + ElfStrDynstr, + ElfStrRel, + ElfStrText, + ElfStrData, + ElfStrBss, + ElfStrSymtab, + ElfStrStrtab, + ElfStrShstrtab, + ElfStrRelPlt, + ElfStrPlt, + NElfStr +}; + +vlong elfstr[NElfStr]; + +static int +needlib(char *name) +{ + char *p; + Sym *s; + + if(*name == '\0') + return 0; + + /* 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 s->value; + return 0; +} + +int nelfsym = 1; + +void +adddynrel(Sym *s, Reloc *r) +{ + USED(s); + USED(r); + diag("adddynrel: unsupported binary format"); +} + +void +adddynsym(Sym *s) +{ + USED(s); + diag("adddynsym: not implemented"); +} + +static void +elfsetupplt(void) +{ + // TODO +} + +int +archreloc(Reloc *r, Sym *s, vlong *val) +{ + USED(r); + USED(s); + USED(val); + return -1; +} + +void +adddynlib(char *lib) +{ + Sym *s; + + if(!needlib(lib)) + return; + + if(iself) { + s = lookup(".dynstr", 0); + if(s->size == 0) + addstring(s, ""); + elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib)); + } else { + diag("adddynlib: unsupported binary format"); + } +} + +void +doelf(void) +{ + Sym *s, *shstrtab, *dynstr; + + if(!iself) + return; + + /* predefine strings we need for section headers */ + shstrtab = lookup(".shstrtab", 0); + shstrtab->type = SELFROSECT; + shstrtab->reachable = 1; + + elfstr[ElfStrEmpty] = addstring(shstrtab, ""); + elfstr[ElfStrText] = addstring(shstrtab, ".text"); + elfstr[ElfStrData] = addstring(shstrtab, ".data"); + elfstr[ElfStrBss] = addstring(shstrtab, ".bss"); + addstring(shstrtab, ".rodata"); + addstring(shstrtab, ".gosymtab"); + addstring(shstrtab, ".gopclntab"); + if(!debug['s']) { + elfstr[ElfStrSymtab] = addstring(shstrtab, ".symtab"); + elfstr[ElfStrStrtab] = addstring(shstrtab, ".strtab"); + } + 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"); + elfstr[ElfStrRelPlt] = addstring(shstrtab, ".rel.plt"); + elfstr[ElfStrPlt] = addstring(shstrtab, ".plt"); + + /* dynamic symbol table - first entry all zeros */ + s = lookup(".dynsym", 0); + s->type = SELFROSECT; + s->reachable = 1; + s->value += ELF32SYMSIZE; + + /* dynamic string table */ + s = lookup(".dynstr", 0); + s->type = SELFROSECT; + s->reachable = 1; + if(s->size == 0) + addstring(s, ""); + dynstr = s; + + /* relocation table */ + s = lookup(".rel", 0); + s->reachable = 1; + s->type = SELFROSECT; + + /* global offset table */ + s = lookup(".got", 0); + s->reachable = 1; + s->type = SELFSECT; // writable + + /* hash */ + s = lookup(".hash", 0); + s->reachable = 1; + s->type = SELFROSECT; + + /* got.plt */ + s = lookup(".got.plt", 0); + s->reachable = 1; + s->type = SELFSECT; // writable + + s = lookup(".plt", 0); + s->reachable = 1; + s->type = SELFROSECT; + + s = lookup(".rel.plt", 0); + s->reachable = 1; + s->type = SELFROSECT; + + elfsetupplt(); + + /* define dynamic elf table */ + s = lookup(".dynamic", 0); + s->reachable = 1; + s->type = SELFSECT; // writable + + /* + * .dynamic table + */ + 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); + if(rpath) + elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath)); + elfwritedynentsym(s, DT_PLTGOT, lookup(".got.plt", 0)); + elfwritedynent(s, DT_PLTREL, DT_REL); + elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rel.plt", 0)); + elfwritedynentsym(s, DT_JMPREL, lookup(".rel.plt", 0)); + elfwritedynent(s, DT_DEBUG, 0); + elfwritedynent(s, DT_NULL, 0); + } +} + +vlong +datoff(vlong addr) +{ + if(addr >= segdata.vaddr) + return addr - segdata.vaddr + segdata.fileoff; + if(addr >= segtext.vaddr) + return addr - segtext.vaddr + segtext.fileoff; + diag("datoff %#x", addr); + return 0; +} + +void +shsym(Elf64_Shdr *sh, Sym *s) +{ + vlong addr; + addr = symaddr(s); + if(sh->flags&SHF_ALLOC) + sh->addr = addr; + sh->off = datoff(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; - long t, etext; - Optab *o; + int32 t; + int a, dynsym; + uint32 fo, symo, startva; + ElfEhdr *eh; + ElfPhdr *ph, *pph; + ElfShdr *sh; + Section *sect; + int o; if(debug['v']) - Bprint(&bso, "%5.2f asm\n", cputime()); + Bprint(&bso, "%5.2f asmb\n", cputime()); Bflush(&bso); - OFFSET = HEADR; - seek(cout, OFFSET, 0); - pc = INITTEXT; - for(p = firstp; p != P; p = p->link) { - if(p->as == ATEXT) { - curtext = p; - autosize = p->to.offset + 4; - } - if(p->pc != pc) { - diag("phase error %lux sb %lux", - p->pc, pc); - if(!debug['a']) - prasm(curp); - pc = p->pc; - } - curp = p; - o = oplook(p); /* could probably avoid this call */ - asmout(p, o); - pc += o->size; + + sect = segtext.sect; + cseek(sect->vaddr - segtext.vaddr + segtext.fileoff); + codeblk(sect->vaddr, sect->len); + + /* output read-only data in text segment (rodata, gosymtab and pclntab) */ + for(sect = sect->next; sect != nil; sect = sect->next) { + cseek(sect->vaddr - segtext.vaddr + segtext.fileoff); + datblk(sect->vaddr, sect->len); } - if(debug['a']) - Bprint(&bso, "\n"); + if(debug['v']) + Bprint(&bso, "%5.2f datblk\n", cputime()); Bflush(&bso); - cflush(); - /* output strings in text segment */ - etext = INITTEXT + textsize; - for(t = pc; t < etext; t += sizeof(buf)-100) { - if(etext-t > sizeof(buf)-100) - datblk(t, sizeof(buf)-100, 1); - else - datblk(t, etext-t, 1); + cseek(segdata.fileoff); + datblk(segdata.vaddr, segdata.filelen); + + /* output read-only data in text segment */ + sect = segtext.sect->next; + cseek(sect->vaddr - segtext.vaddr + segtext.fileoff); + datblk(sect->vaddr, sect->len); + + if(iself) { + /* index of elf text section; needed by asmelfsym, double-checked below */ + /* !debug['d'] causes extra sections before the .text section */ + elftextsh = 2; + if(!debug['d']) { + elftextsh += 10; + if(elfverneed) + elftextsh += 2; + } } - curtext = P; - switch(HEADTYPE) { - case 0: - case 1: - case 2: - case 5: - OFFSET = HEADR+textsize; - seek(cout, OFFSET, 0); - break; - case 3: - OFFSET = rnd(HEADR+textsize, 4096); - seek(cout, OFFSET, 0); - break; - } - if(dlm){ - char buf[8]; - - write(cout, buf, INITDAT-textsize); - textsize = INITDAT; - } - for(t = 0; t < datsize; t += sizeof(buf)-100) { - if(datsize-t > sizeof(buf)-100) - datblk(t, sizeof(buf)-100, 0); - else - datblk(t, datsize-t, 0); - } - + /* output symbol table */ symsize = 0; lcsize = 0; + symo = 0; if(!debug['s']) { + // TODO: rationalize if(debug['v']) Bprint(&bso, "%5.2f sym\n", cputime()); Bflush(&bso); switch(HEADTYPE) { - case 0: - case 1: - case 4: - case 5: + default: + if(iself) + goto ElfSym; + case Hnoheader: + case Hrisc: + case Hixp1200: + case Hipaq: debug['s'] = 1; break; - case 2: - OFFSET = HEADR+textsize+datsize; - seek(cout, OFFSET, 0); + case Hplan9x32: + symo = HEADR+segtext.len+segdata.filelen; break; - case 3: - OFFSET += rnd(datsize, 4096); - seek(cout, OFFSET, 0); + case Hnetbsd: + symo = rnd(segdata.filelen, 4096); + break; + ElfSym: + symo = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen; + symo = rnd(symo, INITRND); break; } - if(!debug['s']) - asmsym(); - if(debug['v']) - Bprint(&bso, "%5.2f pc\n", cputime()); - Bflush(&bso); - if(!debug['s']) - asmlc(); - if(dlm) - asmdyn(); + cseek(symo); + if(iself) { + if(debug['v']) + Bprint(&bso, "%5.2f elfsym\n", cputime()); + asmelfsym(); + cflush(); + cwrite(elfstrdat, elfstrsize); + + // if(debug['v']) + // Bprint(&bso, "%5.2f dwarf\n", cputime()); + // dwarfemitdebugsections(); + } cflush(); - } - else if(dlm){ - seek(cout, HEADR+textsize+datsize, 0); - asmdyn(); - cflush(); + } + cursym = nil; if(debug['v']) Bprint(&bso, "%5.2f header\n", cputime()); Bflush(&bso); - OFFSET = 0; - seek(cout, OFFSET, 0); + cseek(0L); switch(HEADTYPE) { - case 0: /* no header */ + case Hnoheader: /* no header */ break; - case 1: /* aif for risc os */ + case Hrisc: /* aif for risc os */ lputl(0xe1a00000); /* NOP - decompress code */ lputl(0xe1a00000); /* NOP - relocation code */ lputl(0xeb000000 + 12); /* BL - zero init code */ @@ -161,10 +405,10 @@ lputl(0xef000011); /* SWI - exit code */ lputl(textsize+HEADR); /* text size */ - lputl(datsize); /* data size */ + lputl(segdata.filelen); /* data size */ lputl(0); /* sym size */ - lputl(bsssize); /* bss size */ + lputl(segdata.len - segdata.filelen); /* bss size */ lputl(0); /* sym type */ lputl(INITTEXT-HEADR); /* text addr */ lputl(0); /* workspace - ignored */ @@ -178,64 +422,257 @@ lputl(0xe1a00000); /* NOP - zero init code */ lputl(0xe1a0f00e); /* B (R14) - zero init return */ break; - case 2: /* plan 9 */ - if(dlm) - lput(0x80000000|0x647); /* magic */ - else - lput(0x647); /* magic */ + case Hplan9x32: /* plan 9 */ + lput(0x647); /* magic */ lput(textsize); /* sizes */ - lput(datsize); - lput(bsssize); + lput(segdata.filelen); + lput(segdata.len - segdata.filelen); lput(symsize); /* nsyms */ lput(entryvalue()); /* va of entry */ lput(0L); lput(lcsize); break; - case 3: /* boot for NetBSD */ + case Hnetbsd: /* boot for NetBSD */ lput((143<<16)|0413); /* magic */ lputl(rnd(HEADR+textsize, 4096)); - lputl(rnd(datsize, 4096)); - lputl(bsssize); + lputl(rnd(segdata.filelen, 4096)); + lputl(segdata.len - segdata.filelen); lputl(symsize); /* nsyms */ lputl(entryvalue()); /* va of entry */ lputl(0L); lputl(0L); break; - case 4: /* boot for IXP1200 */ + case Hixp1200: /* boot for IXP1200 */ break; - case 5: /* boot for ipaq */ + case Hipaq: /* boot for ipaq */ lputl(0xe3300000); /* nop */ lputl(0xe3300000); /* nop */ lputl(0xe3300000); /* nop */ lputl(0xe3300000); /* nop */ break; + case Hlinux: + /* elf arm */ + eh = getElfEhdr(); + fo = HEADR; + startva = INITTEXT - fo; /* va of byte 0 of file */ + + /* This null SHdr must appear before all others */ + newElfShdr(elfstr[ElfStrEmpty]); + + /* program header info */ + 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; + + /* + * PHDR must be in a loaded segment. Adjust the text + * segment boundaries downwards to include it. + */ + o = segtext.vaddr - pph->vaddr; + segtext.vaddr -= o; + segtext.len += o; + o = segtext.fileoff - pph->off; + segtext.fileoff -= o; + segtext.filelen += o; + + if(!debug['d']) { + /* interpreter for dynamic linking */ + sh = newElfShdr(elfstr[ElfStrInterp]); + sh->type = SHT_PROGBITS; + sh->flags = SHF_ALLOC; + sh->addralign = 1; + if(interpreter == nil) + interpreter = linuxdynld; + elfinterp(sh, startva, interpreter); + + ph = newElfPhdr(); + ph->type = PT_INTERP; + ph->flags = PF_R; + phsh(ph, sh); + } + + elfphload(&segtext); + elfphload(&segdata); + + /* 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; + + sh = newElfShstrtab(elfstr[ElfStrShstrtab]); + sh->type = SHT_STRTAB; + sh->addralign = 1; + shsym(sh, lookup(".shstrtab", 0)); + + if(elftextsh != eh->shnum) + diag("elftextsh = %d, want %d", elftextsh, eh->shnum); + for(sect=segtext.sect; sect!=nil; sect=sect->next) + elfshbits(sect); + for(sect=segdata.sect; sect!=nil; sect=sect->next) + elfshbits(sect); + + if (!debug['s']) { + sh = newElfShdr(elfstr[ElfStrSymtab]); + sh->type = SHT_SYMTAB; + sh->off = symo; + sh->size = symsize; + sh->addralign = 4; + sh->entsize = 16; + sh->link = eh->shnum; // link to strtab + + sh = newElfShdr(elfstr[ElfStrStrtab]); + sh->type = SHT_STRTAB; + sh->off = symo+symsize; + sh->size = elfstrsize; + sh->addralign = 1; + + // dwarfaddelfheaders(); + } + + /* 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; + + eh->type = ET_EXEC; + eh->machine = EM_ARM; + eh->version = EV_CURRENT; + eh->entry = entryvalue(); + + if(pph != nil) { + pph->filesz = eh->phnum * eh->phentsize; + pph->memsz = pph->filesz; + } + + cseek(0); + a = 0; + a += elfwritehdr(); + a += elfwritephdrs(); + a += elfwriteshdrs(); + a += elfwriteinterp(); + if(a > ELFRESERVE) + diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE); + break; } cflush(); + if(debug['c']){ + print("textsize=%d\n", textsize); + print("datsize=%ulld\n", segdata.filelen); + print("bsssize=%ulld\n", segdata.len - segdata.filelen); + print("symsize=%d\n", symsize); + print("lcsize=%d\n", lcsize); + print("total=%lld\n", textsize+segdata.len+symsize+lcsize); + } } +/* void -strnput(char *s, int n) +cput(int32 c) { - for(; *s; s++){ - cput(*s); - n--; - } - for(; n > 0; n--) - cput(0); + *cbp++ = c; + if(--cbc <= 0) + cflush(); } +*/ void -cput(int c) +wput(int32 l) { - cbp[0] = c; - cbp++; - cbc--; + + cbp[0] = l>>8; + cbp[1] = l; + cbp += 2; + cbc -= 2; if(cbc <= 0) cflush(); } + void -wput(long l) +hput(int32 l) { cbp[0] = l>>8; @@ -247,7 +684,7 @@ } void -lput(long l) +lput(int32 l) { cbp[0] = l>>24; @@ -261,359 +698,20 @@ } void -lputl(long l) -{ - - cbp[3] = l>>24; - cbp[2] = l>>16; - cbp[1] = l>>8; - cbp[0] = l; - cbp += 4; - cbc -= 4; - 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); -} - -void nopstat(char *f, Count *c) { if(c->outof) - Bprint(&bso, "%s delay %ld/%ld (%.2f)\n", f, + Bprint(&bso, "%s delay %d/%d (%.2f)\n", f, c->outof - c->count, c->outof, (double)(c->outof - c->count)/c->outof); } void -asmsym(void) +asmout(Prog *p, Optab *o, int32 *out) { - Prog *p; - Auto *a; - Sym *s; - int h; - - s = lookup("etext", 0); - if(s->type == STEXT) - putsymb(s->name, 'T', s->value, s->version); - - for(h=0; hlink) - switch(s->type) { - case SCONST: - putsymb(s->name, 'D', s->value, s->version); - continue; - - case SDATA: - putsymb(s->name, 'D', s->value+INITDAT, s->version); - continue; - - case SBSS: - putsymb(s->name, 'B', s->value+INITDAT, s->version); - continue; - - case SSTRING: - putsymb(s->name, 'T', s->value, s->version); - continue; - - case SFILE: - putsymb(s->name, 'f', s->value, s->version); - continue; - } - - for(p=textp; p!=P; p=p->cond) { - s = p->from.sym; - if(s->type != STEXT && s->type != SLEAF) - continue; - - /* filenames first */ - for(a=p->to.autom; a; a=a->link) - if(a->type == D_FILE) - putsymb(a->asym->name, 'z', a->aoffset, 0); - else - if(a->type == D_FILE1) - putsymb(a->asym->name, 'Z', a->aoffset, 0); - - if(s->type == STEXT) - putsymb(s->name, 'T', s->value, s->version); - else - putsymb(s->name, 'L', s->value, s->version); - - /* frame, auto and param after */ - putsymb(".frame", 'm', p->to.offset+4, 0); - for(a=p->to.autom; a; a=a->link) - if(a->type == D_AUTO) - putsymb(a->asym->name, 'a', -a->aoffset, 0); - else - if(a->type == D_PARAM) - putsymb(a->asym->name, 'p', a->aoffset, 0); - } - if(debug['v'] || debug['n']) - Bprint(&bso, "symsize = %lud\n", symsize); - Bflush(&bso); -} - -void -putsymb(char *s, int t, long v, int ver) -{ - int i, f; - - if(t == 'f') - s++; - lput(v); - if(ver) - t += 'a' - 'A'; - cput(t+0x80); /* 0x80 is variable length */ - - if(t == 'Z' || t == 'z') { - cput(s[0]); - for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) { - cput(s[i]); - cput(s[i+1]); - } - cput(0); - cput(0); - i++; - } - else { - for(i=0; s[i]; i++) - cput(s[i]); - cput(0); - } - symsize += 4 + 1 + i + 1; - - if(debug['n']) { - if(t == 'z' || t == 'Z') { - Bprint(&bso, "%c %.8lux ", t, v); - for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) { - f = ((s[i]&0xff) << 8) | (s[i+1]&0xff); - Bprint(&bso, "/%x", f); - } - Bprint(&bso, "\n"); - return; - } - if(ver) - Bprint(&bso, "%c %.8lux %s<%d>\n", t, v, s, ver); - else - Bprint(&bso, "%c %.8lux %s\n", t, v, s); - } -} - -#define MINLC 4 -void -asmlc(void) -{ - long oldpc, oldlc; - Prog *p; - long v, s; - - oldpc = INITTEXT; - oldlc = 0; - for(p = firstp; p != P; p = p->link) { - if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) { - if(p->as == ATEXT) - curtext = p; - if(debug['L']) - Bprint(&bso, "%6lux %P\n", - p->pc, p); - continue; - } - if(debug['L']) - Bprint(&bso, "\t\t%6ld", lcsize); - v = (p->pc - oldpc) / MINLC; - while(v) { - s = 127; - if(v < 127) - s = v; - cput(s+128); /* 129-255 +pc */ - if(debug['L']) - Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128); - v -= s; - lcsize++; - } - s = p->line - oldlc; - oldlc = p->line; - oldpc = p->pc + MINLC; - if(s > 64 || s < -64) { - cput(0); /* 0 vv +lc */ - cput(s>>24); - cput(s>>16); - cput(s>>8); - cput(s); - if(debug['L']) { - if(s > 0) - Bprint(&bso, " lc+%ld(%d,%ld)\n", - s, 0, s); - else - Bprint(&bso, " lc%ld(%d,%ld)\n", - s, 0, s); - Bprint(&bso, "%6lux %P\n", - p->pc, p); - } - lcsize += 5; - continue; - } - if(s > 0) { - cput(0+s); /* 1-64 +lc */ - if(debug['L']) { - Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s); - Bprint(&bso, "%6lux %P\n", - p->pc, p); - } - } else { - cput(64-s); /* 65-128 -lc */ - if(debug['L']) { - Bprint(&bso, " lc%ld(%ld)\n", s, 64-s); - Bprint(&bso, "%6lux %P\n", - p->pc, p); - } - } - lcsize++; - } - while(lcsize & 1) { - s = 129; - cput(s); - lcsize++; - } - if(debug['v'] || debug['L']) - Bprint(&bso, "lcsize = %ld\n", lcsize); - Bflush(&bso); -} - -void -datblk(long s, long n, int str) -{ - Sym *v; - Prog *p; - char *cast; - long a, l, fl, j, d; - int i, c; - - memset(buf.dbuf, 0, n+100); - for(p = datap; p != P; p = p->link) { - if(str != (p->from.sym->type == SSTRING)) - continue; - curp = p; - a = p->from.sym->value + p->from.offset; - l = a - s; - c = p->reg; - i = 0; - if(l < 0) { - if(l+c <= 0) - continue; - while(l < 0) { - l++; - i++; - } - } - if(l >= n) - 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) { - default: - diag("unknown mode in initialization%P", p); - break; - - case D_FCONST: - switch(c) { - default: - case 4: - fl = ieeedtof(p->to.ieee); - cast = (char*)&fl; - for(; ito.ieee; - for(; ito.sval[i]; - l++; - } - break; - - case D_CONST: - d = p->to.offset; - v = p->to.sym; - if(v) { - switch(v->type) { - case SUNDEF: - ckoff(v, d); - case STEXT: - case SLEAF: - case SSTRING: - d += p->to.sym->value; - break; - case SDATA: - case SBSS: - d += p->to.sym->value + INITDAT; - } - if(dlm) - dynreloc(v, a+INITDAT, 1); - } - cast = (char*)&d; - switch(c) { - default: - diag("bad nuxi %d %d%P", c, i, curp); - break; - case 1: - for(; isize; +if(debug['P']) print("%ux: %P type %d\n", (uint32)(p->pc), p, o->type); switch(o->type) { default: diag("unknown asm %d", o->type); @@ -629,6 +729,7 @@ break; case 0: /* pseudo ops */ +if(debug['G']) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->name, p->from.sym->fnptr); break; case 1: /* op R,[R],R */ @@ -640,7 +741,8 @@ rt = 0; if(p->as == AMOVW || p->as == AMVN) r = 0; - else if(r == NREG) + else + if(r == NREG) r = rt; o1 |= rf | (r<<16) | (rt<<12); break; @@ -689,14 +791,7 @@ case 5: /* bra s */ v = -8; - if(p->cond == UP) { - s = p->to.sym; - if(s->type != SUNDEF) - diag("bad branch sym type"); - v = (ulong)s->value >> (Roffset-2); - dynreloc(s, p->pc, 0); - } - else if(p->cond != P) + if(p->cond != P) v = (p->cond->pc - pc) - 8; o1 = opbra(p->as, p->scond); o1 |= (v >> 2) & 0xffffff; @@ -753,18 +848,17 @@ break; case 11: /* word */ - switch(aclass(&p->to)) { - case C_LCON: - if(!dlm) - break; - if(p->to.name != D_EXTERN && p->to.name != D_STATIC) - break; - case C_ADDR: - if(p->to.sym->type == SUNDEF) - ckoff(p->to.sym, p->to.offset); - dynreloc(p->to.sym, p->pc, 1); + aclass(&p->to); + o1 = instoffset; + if(p->to.sym != S) { + rel = addrel(cursym); + rel->off = pc - cursym->value; + rel->siz = 4; + rel->type = D_ADDR; + rel->sym = p->to.sym; + rel->add = p->to.offset; + o1 = 0; } - o1 = instoffset; break; case 12: /* movw $lcon, reg */ @@ -859,40 +953,6 @@ o1 |= 1<<22; break; - case 22: /* movb/movh/movhu O(R),R -> lr,shl,shr */ - aclass(&p->from); - r = p->from.reg; - if(r == NREG) - r = o->param; - o1 = olr(instoffset, r, p->to.reg, p->scond); - - o2 = oprrr(ASLL, p->scond); - o3 = oprrr(ASRA, p->scond); - r = p->to.reg; - if(p->as == AMOVB) { - o2 |= (24<<7)|(r)|(r<<12); - o3 |= (24<<7)|(r)|(r<<12); - } else { - o2 |= (16<<7)|(r)|(r<<12); - if(p->as == AMOVHU) - o3 = oprrr(ASRL, p->scond); - o3 |= (16<<7)|(r)|(r<<12); - } - break; - - case 23: /* movh/movhu R,O(R) -> sb,sb */ - aclass(&p->to); - r = p->to.reg; - if(r == NREG) - r = o->param; - o1 = osr(AMOVH, p->from.reg, instoffset, r, p->scond); - - o2 = oprrr(ASRL, p->scond); - o2 |= (8<<7)|(p->from.reg)|(REGTMP<<12); - - o3 = osr(AMOVH, REGTMP, instoffset+1, r, p->scond); - break; - case 30: /* mov/movb/movbu R,L(R) */ o1 = omvl(p, &p->to, REGTMP); if(!o1) @@ -906,7 +966,6 @@ break; case 31: /* mov/movbu L(R),R -> lr[b] */ - case 32: /* movh/movb L(R),R -> lr[b] */ o1 = omvl(p, &p->from, REGTMP); if(!o1) break; @@ -916,55 +975,8 @@ o2 = olrr(REGTMP,r, p->to.reg, p->scond); if(p->as == AMOVBU || p->as == AMOVB) o2 |= 1<<22; - if(o->type == 31) - break; - - o3 = oprrr(ASLL, p->scond); - - if(p->as == AMOVBU || p->as == AMOVHU) - o4 = oprrr(ASRL, p->scond); - else - o4 = oprrr(ASRA, p->scond); - - r = p->to.reg; - o3 |= (r)|(r<<12); - o4 |= (r)|(r<<12); - if(p->as == AMOVB || p->as == AMOVBU) { - o3 |= (24<<7); - o4 |= (24<<7); - } else { - o3 |= (16<<7); - o4 |= (16<<7); - } break; - case 33: /* movh/movhu R,L(R) -> sb, sb */ - o1 = omvl(p, &p->to, REGTMP); - if(!o1) - break; - r = p->to.reg; - if(r == NREG) - r = o->param; - o2 = osrr(p->from.reg, REGTMP, r, p->scond); - o2 |= (1<<22) ; - - o3 = oprrr(ASRL, p->scond); - o3 |= (8<<7)|(p->from.reg)|(p->from.reg<<12); - o3 |= (1<<6); /* ROR 8 */ - - o4 = oprrr(AADD, p->scond); - o4 |= (REGTMP << 12) | (REGTMP << 16); - o4 |= immrot(1); - - o5 = osrr(p->from.reg, REGTMP,r,p->scond); - o5 |= (1<<22); - - o6 = oprrr(ASRL, p->scond); - o6 |= (24<<7)|(p->from.reg)|(p->from.reg<<12); - o6 |= (1<<6); /* ROL 8 */ - - break; - case 34: /* mov $lacon,R */ o1 = omvl(p, &p->from, REGTMP); if(!o1) @@ -1066,7 +1078,7 @@ o1 = ofsr(p->as, p->to.reg, v, r, p->scond, p) | (1<<20); break; - case 52: /* floating point store, long offset UGLY */ + case 52: /* floating point store, int32 offset UGLY */ o1 = omvl(p, &p->to, REGTMP); if(!o1) break; @@ -1077,7 +1089,7 @@ o3 = ofsr(p->as, p->from.reg, 0, REGTMP, p->scond, p); break; - case 53: /* floating point load, long offset UGLY */ + case 53: /* floating point load, int32 offset UGLY */ o1 = omvl(p, &p->from, REGTMP); if(!o1) break; @@ -1090,41 +1102,17 @@ case 54: /* floating point arith */ o1 = oprrr(p->as, p->scond); - if(p->from.type == D_FCONST) { - rf = chipfloat(p->from.ieee); - if(rf < 0){ - diag("invalid floating-point immediate\n%P", p); - rf = 0; - } - rf |= (1<<3); - } else - rf = p->from.reg; + rf = p->from.reg; rt = p->to.reg; r = p->reg; - if(p->to.type == D_NONE) - rt = 0; /* CMP[FD] */ - else if(o1 & (1<<15)) - r = 0; /* monadic */ - else if(r == NREG) + if(r == NREG) { r = rt; + if(p->as == AMOVF || p->as == AMOVD || p->as == ASQRTF || p->as == ASQRTD) + r = 0; + } o1 |= rf | (r<<16) | (rt<<12); break; - case 55: /* floating point fix and float */ - o1 = oprrr(p->as, p->scond); - rf = p->from.reg; - rt = p->to.reg; - if(p->to.type == D_NONE){ - rt = 0; - diag("to.type==D_NONE (asm/fp)"); - } - if(p->from.type == D_REG) - o1 |= (rf<<12) | (rt<<16); - else - o1 |= rf | (rt<<12); - break; - - /* old arm 7500 fp using coproc 1 (1<<8) */ case 56: /* move to FP[CS]R */ o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4); o1 |= ((p->to.reg+1)<<21) | (p->from.reg << 12); @@ -1184,11 +1172,8 @@ break; case 63: /* bcase */ - if(p->cond != P) { + if(p->cond != P) o1 = p->cond->pc; - if(dlm) - dynreloc(S, p->pc, 1); - } break; /* reloc ops */ @@ -1200,54 +1185,12 @@ break; case 65: /* mov/movbu addr,R */ - case 66: /* movh/movhu/movb addr,R */ o1 = omvl(p, &p->from, REGTMP); if(!o1) break; o2 = olr(0, REGTMP, p->to.reg, p->scond); if(p->as == AMOVBU || p->as == AMOVB) o2 |= 1<<22; - if(o->type == 65) - break; - - o3 = oprrr(ASLL, p->scond); - - if(p->as == AMOVBU || p->as == AMOVHU) - o4 = oprrr(ASRL, p->scond); - else - o4 = oprrr(ASRA, p->scond); - - r = p->to.reg; - o3 |= (r)|(r<<12); - o4 |= (r)|(r<<12); - if(p->as == AMOVB || p->as == AMOVBU) { - o3 |= (24<<7); - o4 |= (24<<7); - } else { - o3 |= (16<<7); - o4 |= (16<<7); - } - break; - - case 67: /* movh/movhu R,addr -> sb, sb */ - o1 = omvl(p, &p->to, REGTMP); - if(!o1) - break; - o2 = osr(p->as, p->from.reg, 0, REGTMP, p->scond); - - o3 = oprrr(ASRL, p->scond); - o3 |= (8<<7)|(p->from.reg)|(p->from.reg<<12); - o3 |= (1<<6); /* ROR 8 */ - - o4 = oprrr(AADD, p->scond); - o4 |= (REGTMP << 12) | (REGTMP << 16); - o4 |= immrot(1); - - o5 = osr(p->as, p->from.reg, 0, REGTMP, p->scond); - - o6 = oprrr(ASRL, p->scond); - o6 |= (24<<7)|(p->from.reg)|(p->from.reg<<12); - o6 |= (1<<6); /* ROL 8 */ break; case 68: /* floating point store -> ADDR */ @@ -1271,7 +1214,7 @@ if(r == NREG) r = o->param; o1 = oshr(p->from.reg, instoffset, r, p->scond); - break; + break; case 71: /* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */ aclass(&p->from); r = p->from.reg; @@ -1291,7 +1234,7 @@ if(r == NREG) r = o->param; o2 = oshrr(p->from.reg, REGTMP,r, p->scond); - break; + break; case 73: /* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */ o1 = omvl(p, &p->from, REGTMP); if(!o1) @@ -1305,38 +1248,204 @@ else if(p->as == AMOVH) o2 ^= (1<<6); break; + case 74: /* bx $I */ + diag("ABX $I"); + break; + case 75: /* bx O(R) */ + aclass(&p->to); + if(instoffset != 0) + diag("non-zero offset in ABX"); +/* + o1 = oprrr(AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR + o2 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | p->to.reg; // BX R +*/ + // p->to.reg may be REGLINK + o1 = oprrr(AADD, p->scond); + o1 |= immrot(instoffset); + o1 |= p->to.reg << 16; + o1 |= REGTMP << 12; + o2 = oprrr(AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR + o3 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | REGTMP; // BX Rtmp + break; + case 76: /* bx O(R) when returning from fn*/ + diag("ABXRET"); + break; + case 77: /* ldrex oreg,reg */ + aclass(&p->from); + if(instoffset != 0) + diag("offset must be zero in LDREX"); + o1 = (0x19<<20) | (0xf9f); + o1 |= p->from.reg << 16; + o1 |= p->to.reg << 12; + o1 |= (p->scond & C_SCOND) << 28; + break; + case 78: /* strex reg,oreg,reg */ + aclass(&p->from); + if(instoffset != 0) + diag("offset must be zero in STREX"); + o1 = (0x18<<20) | (0xf90); + o1 |= p->from.reg << 16; + o1 |= p->reg << 0; + o1 |= p->to.reg << 12; + o1 |= (p->scond & C_SCOND) << 28; + break; + case 80: /* fmov zfcon,freg */ + if(p->as == AMOVD) { + o1 = 0xeeb00b00; // VMOV imm 64 + o2 = oprrr(ASUBD, p->scond); + } else { + o1 = 0x0eb00a00; // VMOV imm 32 + o2 = oprrr(ASUBF, p->scond); + } + v = 0x70; // 1.0 + r = p->to.reg; + + // movf $1.0, r + o1 |= (p->scond & C_SCOND) << 28; + o1 |= r << 12; + o1 |= (v&0xf) << 0; + o1 |= (v&0xf0) << 12; + + // subf r,r,r + o2 |= r | (r<<16) | (r<<12); + break; + case 81: /* fmov sfcon,freg */ + o1 = 0x0eb00a00; // VMOV imm 32 + if(p->as == AMOVD) + o1 = 0xeeb00b00; // VMOV imm 64 + o1 |= (p->scond & C_SCOND) << 28; + o1 |= p->to.reg << 12; + v = chipfloat(&p->from.ieee); + o1 |= (v&0xf) << 0; + o1 |= (v&0xf0) << 12; + break; + case 82: /* fcmp freg,freg, */ + o1 = oprrr(p->as, p->scond); + o1 |= (p->reg<<12) | (p->from.reg<<0); + o2 = 0x0ef1fa10; // VMRS R15 + o2 |= (p->scond & C_SCOND) << 28; + break; + case 83: /* fcmp freg,, */ + o1 = oprrr(p->as, p->scond); + o1 |= (p->from.reg<<12) | (1<<16); + o2 = 0x0ef1fa10; // VMRS R15 + o2 |= (p->scond & C_SCOND) << 28; + break; + case 84: /* movfw freg,freg - truncate float-to-fix */ + o1 = oprrr(p->as, p->scond); + o1 |= (p->from.reg<<0); + o1 |= (p->to.reg<<12); + break; + case 85: /* movwf freg,freg - fix-to-float */ + o1 = oprrr(p->as, p->scond); + o1 |= (p->from.reg<<0); + o1 |= (p->to.reg<<12); + break; + case 86: /* movfw freg,reg - truncate float-to-fix */ + // macro for movfw freg,FTMP; movw FTMP,reg + o1 = oprrr(p->as, p->scond); + o1 |= (p->from.reg<<0); + o1 |= (FREGTMP<<12); + o2 = oprrr(AMOVFW+AEND, p->scond); + o2 |= (FREGTMP<<16); + o2 |= (p->to.reg<<12); + break; + case 87: /* movwf reg,freg - fix-to-float */ + // macro for movw reg,FTMP; movwf FTMP,freg + o1 = oprrr(AMOVWF+AEND, p->scond); + o1 |= (p->from.reg<<12); + o1 |= (FREGTMP<<16); + o2 = oprrr(p->as, p->scond); + o2 |= (FREGTMP<<0); + o2 |= (p->to.reg<<12); + break; + case 88: /* movw reg,freg */ + o1 = oprrr(AMOVWF+AEND, p->scond); + o1 |= (p->from.reg<<12); + o1 |= (p->to.reg<<16); + break; + case 89: /* movw freg,reg */ + o1 = oprrr(AMOVFW+AEND, p->scond); + o1 |= (p->from.reg<<16); + o1 |= (p->to.reg<<12); + break; + case 90: /* tst reg */ + o1 = oprrr(ACMP+AEND, p->scond); + o1 |= p->from.reg<<16; + break; + case 91: /* ldrexd oreg,reg */ + aclass(&p->from); + if(instoffset != 0) + diag("offset must be zero in LDREX"); + o1 = (0x1b<<20) | (0xf9f); + o1 |= p->from.reg << 16; + o1 |= p->to.reg << 12; + o1 |= (p->scond & C_SCOND) << 28; + break; + case 92: /* strexd reg,oreg,reg */ + aclass(&p->from); + if(instoffset != 0) + diag("offset must be zero in STREX"); + o1 = (0x1a<<20) | (0xf90); + o1 |= p->from.reg << 16; + o1 |= p->reg << 0; + o1 |= p->to.reg << 12; + o1 |= (p->scond & C_SCOND) << 28; + break; + case 93: /* movb/movh/movhu addr,R -> ldrsb/ldrsh/ldrh */ + o1 = omvl(p, &p->from, REGTMP); + if(!o1) + break; + o2 = olhr(0, REGTMP, p->to.reg, p->scond); + if(p->as == AMOVB) + o2 ^= (1<<5)|(1<<6); + else if(p->as == AMOVH) + o2 ^= (1<<6); + break; + case 94: /* movh/movhu R,addr -> strh */ + o1 = omvl(p, &p->to, REGTMP); + if(!o1) + break; + o2 = oshr(p->from.reg, 0, REGTMP, p->scond); + break; } + + out[0] = o1; + out[1] = o2; + out[2] = o3; + out[3] = o4; + out[4] = o5; + out[5] = o6; + return; - if(debug['a'] > 1) - Bprint(&bso, "%2d ", o->type); - +#ifdef NOTDEF v = p->pc; switch(o->size) { default: if(debug['a']) - Bprint(&bso, " %.8lux:\t\t%P\n", v, p); + Bprint(&bso, " %.8ux:\t\t%P\n", v, p); break; case 4: if(debug['a']) - Bprint(&bso, " %.8lux: %.8lux\t%P\n", v, o1, p); + Bprint(&bso, " %.8ux: %.8ux\t%P\n", v, o1, p); lputl(o1); break; case 8: if(debug['a']) - Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n", v, o1, o2, p); + Bprint(&bso, " %.8ux: %.8ux %.8ux%P\n", v, o1, o2, p); lputl(o1); lputl(o2); break; case 12: if(debug['a']) - Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux%P\n", v, o1, o2, o3, p); + Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux%P\n", v, o1, o2, o3, p); lputl(o1); lputl(o2); lputl(o3); break; case 16: if(debug['a']) - Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux%P\n", + Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux%P\n", v, o1, o2, o3, o4, p); lputl(o1); lputl(o2); @@ -1345,7 +1454,7 @@ break; case 20: if(debug['a']) - Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux%P\n", + Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux%P\n", v, o1, o2, o3, o4, o5, p); lputl(o1); lputl(o2); @@ -1355,7 +1464,7 @@ break; case 24: if(debug['a']) - Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux%P\n", + Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux %.8ux%P\n", v, o1, o2, o3, o4, o5, o6, p); lputl(o1); lputl(o2); @@ -1365,12 +1474,13 @@ lputl(o6); break; } +#endif } -long +int32 oprrr(int a, int sc) { - long o; + int32 o; o = (sc & C_SCOND) << 28; if(sc & C_SBIT) @@ -1406,34 +1516,62 @@ case ASRA: return o | (0xd<<21) | (2<<5); case ASWI: return o | (0xf<<24); - /* old arm 7500 fp using coproc 1 (1<<8) */ - case AADDD: return o | (0xe<<24) | (0x0<<20) | (1<<8) | (1<<7); - case AADDF: return o | (0xe<<24) | (0x0<<20) | (1<<8); - case AMULD: return o | (0xe<<24) | (0x1<<20) | (1<<8) | (1<<7); - case AMULF: return o | (0xe<<24) | (0x1<<20) | (1<<8); - case ASUBD: return o | (0xe<<24) | (0x2<<20) | (1<<8) | (1<<7); - case ASUBF: return o | (0xe<<24) | (0x2<<20) | (1<<8); - case ADIVD: return o | (0xe<<24) | (0x4<<20) | (1<<8) | (1<<7); - case ADIVF: return o | (0xe<<24) | (0x4<<20) | (1<<8); - case ACMPD: - case ACMPF: return o | (0xe<<24) | (0x9<<20) | (0xF<<12) | (1<<8) | (1<<4); /* arguably, ACMPF should expand to RNDF, CMPD */ + case AADDD: return o | (0xe<<24) | (0x3<<20) | (0xb<<8) | (0<<4); + case AADDF: return o | (0xe<<24) | (0x3<<20) | (0xa<<8) | (0<<4); + case ASUBD: return o | (0xe<<24) | (0x3<<20) | (0xb<<8) | (4<<4); + case ASUBF: return o | (0xe<<24) | (0x3<<20) | (0xa<<8) | (4<<4); + case AMULD: return o | (0xe<<24) | (0x2<<20) | (0xb<<8) | (0<<4); + case AMULF: return o | (0xe<<24) | (0x2<<20) | (0xa<<8) | (0<<4); + case ADIVD: return o | (0xe<<24) | (0x8<<20) | (0xb<<8) | (0<<4); + case ADIVF: return o | (0xe<<24) | (0x8<<20) | (0xa<<8) | (0<<4); + case ASQRTD: return o | (0xe<<24) | (0xb<<20) | (1<<16) | (0xb<<8) | (0xc<<4); + case ASQRTF: return o | (0xe<<24) | (0xb<<20) | (1<<16) | (0xa<<8) | (0xc<<4); + case ACMPD: return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xb<<8) | (0xc<<4); + case ACMPF: return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xa<<8) | (0xc<<4); - case AMOVF: - case AMOVDF: return o | (0xe<<24) | (0x0<<20) | (1<<15) | (1<<8); - case AMOVD: - case AMOVFD: return o | (0xe<<24) | (0x0<<20) | (1<<15) | (1<<8) | (1<<7); + case AMOVF: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xa<<8) | (4<<4); + case AMOVD: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xb<<8) | (4<<4); - case AMOVWF: return o | (0xe<<24) | (0<<20) | (1<<8) | (1<<4); - case AMOVWD: return o | (0xe<<24) | (0<<20) | (1<<8) | (1<<4) | (1<<7); - case AMOVFW: return o | (0xe<<24) | (1<<20) | (1<<8) | (1<<4); - case AMOVDW: return o | (0xe<<24) | (1<<20) | (1<<8) | (1<<4) | (1<<7); + case AMOVDF: return o | (0xe<<24) | (0xb<<20) | (7<<16) | (0xa<<8) | (0xc<<4) | + (1<<8); // dtof + case AMOVFD: return o | (0xe<<24) | (0xb<<20) | (7<<16) | (0xa<<8) | (0xc<<4) | + (0<<8); // dtof + + case AMOVWF: + if((sc & C_UBIT) == 0) + o |= 1<<7; /* signed */ + return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) | + (0<<18) | (0<<8); // toint, double + case AMOVWD: + if((sc & C_UBIT) == 0) + o |= 1<<7; /* signed */ + return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) | + (0<<18) | (1<<8); // toint, double + + case AMOVFW: + if((sc & C_UBIT) == 0) + o |= 1<<16; /* signed */ + return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) | + (1<<18) | (0<<8) | (1<<7); // toint, double, trunc + case AMOVDW: + if((sc & C_UBIT) == 0) + o |= 1<<16; /* signed */ + return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) | + (1<<18) | (1<<8) | (1<<7); // toint, double, trunc + + case AMOVWF+AEND: // copy WtoF + return o | (0xe<<24) | (0x0<<20) | (0xb<<8) | (1<<4); + case AMOVFW+AEND: // copy FtoW + return o | (0xe<<24) | (0x1<<20) | (0xb<<8) | (1<<4); + case ACMP+AEND: // cmp imm + return o | (0x3<<24) | (0x5<<20); } diag("bad rrr %d", a); prasm(curp); return 0; } -long +int32 opbra(int a, int sc) { @@ -1468,10 +1606,10 @@ return 0; } -long -olr(long v, int b, int r, int sc) +int32 +olr(int32 v, int b, int r, int sc) { - long o; + int32 o; if(sc & C_SBIT) diag(".S on LDR/STR instruction"); @@ -1482,23 +1620,24 @@ o |= 1 << 23; if(sc & C_WBIT) o |= 1 << 21; - o |= (0x1<<26) | (1<<20); + o |= (1<<26) | (1<<20); if(v < 0) { + if(sc & C_UBIT) diag(".U on neg offset"); v = -v; o ^= 1 << 23; } - if(v >= (1<<12)) - diag("literal span too large: %ld (R%d)\n%P", v, b, PP); + if(v >= (1<<12) || v < 0) + diag("literal span too large: %d (R%d)\n%P", v, b, PP); o |= v; o |= b << 16; o |= r << 12; return o; } -long -olhr(long v, int b, int r, int sc) +int32 +olhr(int32 v, int b, int r, int sc) { - long o; + int32 o; if(sc & C_SBIT) diag(".S on LDRH/STRH instruction"); @@ -1512,18 +1651,18 @@ v = -v; o ^= 1 << 23; } - if(v >= (1<<8)) - diag("literal span too large: %ld (R%d)\n%P", v, b, PP); + if(v >= (1<<8) || v < 0) + diag("literal span too large: %d (R%d)\n%P", v, b, PP); o |= (v&0xf)|((v>>4)<<8)|(1<<22); o |= b << 16; o |= r << 12; return o; } -long -osr(int a, int r, long v, int b, int sc) +int32 +osr(int a, int r, int32 v, int b, int sc) { - long o; + int32 o; o = olr(v, b, r, sc) ^ (1<<20); if(a != AMOVW) @@ -1531,46 +1670,46 @@ return o; } -long -oshr(int r, long v, int b, int sc) +int32 +oshr(int r, int32 v, int b, int sc) { - long o; + int32 o; o = olhr(v, b, r, sc) ^ (1<<20); return o; } - -long + +int32 osrr(int r, int i, int b, int sc) { return olr(i, b, r, sc) ^ ((1<<25) | (1<<20)); } -long +int32 oshrr(int r, int i, int b, int sc) { return olhr(i, b, r, sc) ^ ((1<<22) | (1<<20)); } -long +int32 olrr(int i, int b, int r, int sc) { return olr(i, b, r, sc) ^ (1<<25); } -long +int32 olhrr(int i, int b, int r, int sc) { return olhr(i, b, r, sc) ^ (1<<22); } -long -ofsr(int a, int r, long v, int b, int sc, Prog *p) +int32 +ofsr(int a, int r, int32 v, int b, int sc, Prog *p) { - long o; + int32 o; if(sc & C_SBIT) diag(".S on FLDR/FSTR instruction"); @@ -1579,35 +1718,35 @@ o |= 1 << 24; if(sc & C_WBIT) o |= 1 << 21; - o |= (6<<25) | (1<<24) | (1<<23); + o |= (6<<25) | (1<<24) | (1<<23) | (10<<8); if(v < 0) { v = -v; o ^= 1 << 23; } if(v & 3) - diag("odd offset for floating point op: %ld\n%P", v, p); - else if(v >= (1<<10)) - diag("literal span too large: %ld\n%P", v, p); + diag("odd offset for floating point op: %d\n%P", v, p); + else + if(v >= (1<<10) || v < 0) + diag("literal span too large: %d\n%P", v, p); o |= (v>>2) & 0xFF; o |= b << 16; o |= r << 12; - o |= 1 << 8; switch(a) { default: diag("bad fst %A", a); case AMOVD: - o |= 1<<15; + o |= 1 << 8; case AMOVF: break; } return o; } -long +int32 omvl(Prog *p, Adr *a, int dr) -{ - long v, o1; +{ + int32 v, o1; if(!p->cond) { aclass(a); v = immrot(~instoffset); @@ -1626,27 +1765,115 @@ return o1; } -static Ieee chipfloats[] = { - {0x00000000, 0x00000000}, /* 0 */ - {0x00000000, 0x3ff00000}, /* 1 */ - {0x00000000, 0x40000000}, /* 2 */ - {0x00000000, 0x40080000}, /* 3 */ - {0x00000000, 0x40100000}, /* 4 */ - {0x00000000, 0x40140000}, /* 5 */ - {0x00000000, 0x3fe00000}, /* .5 */ - {0x00000000, 0x40240000}, /* 10 */ -}; +int +chipzero(Ieee *e) +{ + if(e->l != 0 || e->h != 0) + return -1; + return 0; +} int chipfloat(Ieee *e) { - Ieee *p; int n; + ulong h; - for(n = sizeof(chipfloats)/sizeof(chipfloats[0]); --n >= 0;){ - p = &chipfloats[n]; - if(p->l == e->l && p->h == e->h) - return n; - } + if(e->l != 0 || (e->h&0xffff) != 0) + goto no; + h = e->h & 0x7fc00000; + if(h != 0x40000000 && h != 0x3fc00000) + goto no; + n = 0; + + // sign bit (a) + if(e->h & 0x80000000) + n |= 1<<7; + + // exp sign bit (b) + if(h == 0x3fc00000) + n |= 1<<6; + + // rest of exp and mantissa (cd-efgh) + n |= (e->h >> 16) & 0x3f; + +//print("match %.8lux %.8lux %d\n", e->l, e->h, n); + return n; + +no: return -1; } + + +void +genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*)) +{ + Auto *a; + Sym *s; + int h; + + s = lookup("etext", 0); + if(s->type == STEXT) + put(s, s->name, 'T', s->value, s->size, s->version, 0); + + for(h=0; hhash) { + if(s->hide) + continue; + switch(s->type) { + case SCONST: + case SRODATA: + case SDATA: + case SELFROSECT: + case STYPE: + case SSTRING: + case SGOSTRING: + if(!s->reachable) + continue; + put(s, s->name, 'D', s->value, s->size, s->version, s->gotype); + continue; + + case SBSS: + if(!s->reachable) + continue; + put(s, s->name, 'B', s->value, s->size, s->version, s->gotype); + continue; + + case SFILE: + put(nil, s->name, 'f', s->value, 0, s->version, 0); + continue; + } + } + } + + for(s = textp; s != nil; s = s->next) { + /* filenames first */ + for(a=s->autom; a; a=a->link) + if(a->type == D_FILE) + put(nil, a->asym->name, 'z', a->aoffset, 0, 0, 0); + else + if(a->type == D_FILE1) + put(nil, a->asym->name, 'Z', a->aoffset, 0, 0, 0); + + put(s, s->name, 'T', s->value, s->size, s->version, s->gotype); + + /* frame, auto and param after */ + put(nil, ".frame", 'm', s->text->to.offset+4, 0, 0, 0); + + for(a=s->autom; a; a=a->link) + if(a->type == D_AUTO) + put(nil, a->asym->name, 'a', -a->aoffset, 0, 0, a->gotype); + else + if(a->type == D_PARAM) + put(nil, a->asym->name, 'p', a->aoffset, 0, 0, a->gotype); + } + if(debug['v'] || debug['n']) + Bprint(&bso, "symsize = %ud\n", symsize); + Bflush(&bso); +} + +void +setpersrc(Sym *s) +{ + USED(s); +} diff -r d8d00747375b sys/src/cmd/5l/compat.c --- a/sys/src/cmd/5l/compat.c Thu Sep 29 03:00:00 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -#include "l.h" - -/* - * fake malloc - */ -void* -malloc(ulong n) -{ - void *p; - - while(n & 7) - n++; - while(nhunk < n) - gethunk(); - p = hunk; - nhunk -= n; - hunk += n; - return p; -} - -void -free(void *p) -{ - USED(p); -} - -void* -calloc(ulong m, ulong n) -{ - void *p; - - n *= m; - p = malloc(n); - memset(p, 0, n); - return p; -} - -void* -realloc(void *p, ulong n) -{ - fprint(2, "realloc(0x%p %ld) called\n", p, n); - abort(); - return 0; -} - -void* -mysbrk(ulong size) -{ - return sbrk(size); -} - -void -setmalloctag(void *v, ulong pc) -{ - USED(v, pc); -} diff -r d8d00747375b sys/src/cmd/5l/l.h --- a/sys/src/cmd/5l/l.h Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/5l/l.h Mon Nov 14 17:35:25 2011 +0100 @@ -1,17 +1,58 @@ +// Inferno utils/5l/l.h +// http://code.google.com/p/inferno-os/source/browse/utils/5l/l.h +// +// 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 #include #include -#include "../5c/5.out.h" +#include "5.out.h" + +enum +{ + thechar = '5', + PtrSize = 4 +}; #ifndef EXTERN #define EXTERN extern #endif +/* do not undefine this - code will be removed eventually */ +#define CALLEEBX + +#define dynptrsize 0 typedef struct Adr Adr; typedef struct Sym Sym; typedef struct Autom Auto; typedef struct Prog Prog; +typedef struct Reloc Reloc; typedef struct Optab Optab; typedef struct Oprang Oprang; typedef uchar Opcross[32][2][32]; @@ -19,33 +60,41 @@ #define P ((Prog*)0) #define S ((Sym*)0) -#define TNAME (curtext&&curtext->from.sym?curtext->from.sym->name:noname) +#define TNAME (cursym?cursym->name:noname) struct Adr { union { - long u0offset; + int32 u0offset; char* u0sval; - Ieee* u0ieee; + Ieee u0ieee; + char* u0sbig; } u0; - union - { - Auto* u1autom; - Sym* u1sym; - } u1; + Sym* sym; char type; + uchar index; // not used on arm, required by ld/go.c char reg; char name; + int32 offset2; // argsize char class; + Sym* gotype; }; #define offset u0.u0offset #define sval u0.u0sval +#define scon sval #define ieee u0.u0ieee +#define sbig u0.u0sbig -#define autom u1.u1autom -#define sym u1.u1sym +struct Reloc +{ + int32 off; + uchar siz; + int16 type; + int32 add; + Sym* sym; +}; struct Prog { @@ -53,34 +102,71 @@ Adr to; union { - long u0regused; + int32 u0regused; Prog* u0forwd; } u0; Prog* cond; Prog* link; - long pc; - long line; + Prog* dlink; + int32 pc; + int32 line; + int32 spadj; uchar mark; uchar optab; uchar as; uchar scond; uchar reg; + uchar align; }; + #define regused u0.u0regused #define forwd u0.u0forwd +#define datasize reg +#define textflag reg + +#define iscall(p) ((p)->as == ABL) struct Sym { - char *name; + char* name; short type; short version; - short become; - short frame; - uchar subtype; - ushort file; - long value; - long sig; - Sym* link; + uchar dupok; + uchar reachable; + uchar dynexport; + uchar leaf; + uchar stkcheck; + uchar hide; + int32 dynid; + int32 plt; + int32 got; + int32 value; + int32 sig; + int32 size; + uchar special; + uchar fnptr; // used as fn ptr + Sym* hash; // in hash table + Sym* allsym; // in all symbol list + Sym* next; // in text or data list + Sym* sub; // in SSUB list + Sym* outer; // container of sub + Sym* gotype; + char* file; + char* dynimpname; + char* dynimplib; + char* dynimpvers; + + // STEXT + Auto* autom; + Prog* text; + + // SDATA, SBSS + uchar* p; + int32 np; + int32 maxp; + Reloc* r; + int32 nr; + int32 maxr; }; #define SIGNINTERN (1729*325*1729) @@ -89,16 +175,17 @@ { Sym* asym; Auto* link; - long aoffset; + int32 aoffset; short type; + Sym* gotype; }; struct Optab { char as; - char a1; + uchar a1; char a2; - char a3; - char type; + uchar a3; + uchar type; char size; char param; char flag; @@ -110,30 +197,15 @@ }; struct Count { - long count; - long outof; + int32 count; + int32 outof; }; enum { - STEXT = 1, - SDATA, - SBSS, - SDATA1, - SXREF, - SLEAF, - SFILE, - SCONST, - SSTRING, - SUNDEF, - - SIMPORT, - SEXPORT, - LFROM = 1<<0, LTO = 1<<1, LPOOL = 1<<2, - V4 = 1<<3, /* arm v4 arch */ C_NONE = 0, C_REG, @@ -147,14 +219,13 @@ C_NCON, /* ~RCON */ C_SCON, /* 0xffff */ C_LCON, - C_FCON, + C_ZFCON, + C_SFCON, + C_LFCON, C_RACON, C_LACON, - C_RECON, - C_LECON, - C_SBRA, C_LBRA, @@ -164,12 +235,6 @@ C_SAUTO, /* -0xfff to 0xfff */ C_LAUTO, - C_HEXT, - C_FEXT, - C_HFEXT, - C_SEXT, - C_LEXT, - C_HOREG, C_FOREG, C_HFOREG, @@ -178,7 +243,11 @@ C_SROREG, /* both S and R */ C_LOREG, - C_ADDR, /* relocatable address */ + C_PC, + C_SP, + C_HREG, + + C_ADDR, /* reference to relocatable address */ C_GOK, @@ -187,96 +256,53 @@ LABEL = 1<<1, LEAF = 1<<2, - BIG = (1<<12)-4, STRINGSZ = 200, - NHASH = 10007, - NHUNK = 100000, MINSIZ = 64, NENT = 100, MAXIO = 8192, MAXHIST = 20, /* limit of path elements for history symbols */ - - Roffset = 22, /* no. bits for offset in relocation address */ - Rindex = 10, /* no. bits for index in relocation address */ + MINLC = 4, }; -EXTERN union -{ - struct - { - uchar obuf[MAXIO]; /* output buffer */ - uchar ibuf[MAXIO]; /* input buffer */ - } u; - char dbuf[1]; -} buf; +#ifndef COFFCVT -#define cbuf u.obuf -#define xbuf u.ibuf - -EXTERN long HEADR; /* length of header */ +EXTERN int32 HEADR; /* length of header */ EXTERN int HEADTYPE; /* type of header */ -EXTERN long INITDAT; /* data location */ -EXTERN long INITRND; /* data round above text location */ -EXTERN long INITTEXT; /* text location */ +EXTERN int32 INITDAT; /* data location */ +EXTERN int32 INITRND; /* data round above text location */ +EXTERN int32 INITTEXT; /* text location */ EXTERN char* INITENTRY; /* entry point */ -EXTERN long autosize; -EXTERN Biobuf bso; -EXTERN long bsssize; -EXTERN int cbc; -EXTERN uchar* cbp; -EXTERN int cout; +EXTERN int32 autosize; EXTERN Auto* curauto; EXTERN Auto* curhist; EXTERN Prog* curp; -EXTERN Prog* curtext; -EXTERN Prog* datap; -EXTERN long datsize; +EXTERN Sym* cursym; +EXTERN Sym* datap; +EXTERN int32 elfdatsize; EXTERN char debug[128]; -EXTERN Prog* etextp; -EXTERN Prog* firstp; -EXTERN char fnuxi4[4]; -EXTERN char fnuxi8[8]; +EXTERN Sym* etextp; EXTERN char* noname; -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* hunk; -EXTERN char inuxi1[1]; -EXTERN char inuxi2[2]; -EXTERN char inuxi4[4]; EXTERN Prog* lastp; -EXTERN long lcsize; +EXTERN int32 lcsize; EXTERN char literal[32]; EXTERN int nerrors; -EXTERN long nhunk; -EXTERN long instoffset; +EXTERN int32 instoffset; EXTERN Opcross opcross[8]; EXTERN Oprang oprange[ALAST]; EXTERN char* outfile; -EXTERN long pc; +EXTERN int32 pc; EXTERN uchar repop[ALAST]; -EXTERN long symsize; -EXTERN Prog* textp; -EXTERN long textsize; -EXTERN long thunk; +EXTERN char* interpreter; +EXTERN char* rpath; +EXTERN uint32 stroffset; +EXTERN int32 symsize; +EXTERN Sym* textp; +EXTERN int32 textsize; EXTERN int version; EXTERN char xcmp[C_GOK+1][C_GOK+1]; EXTERN Prog zprg; EXTERN int dtype; -EXTERN int armv4; - -EXTERN int doexp, dlm; -EXTERN int imports, nimports; -EXTERN int exports, nexports; -EXTERN char* EXPTAB; -EXTERN Prog undefp; - -#define UP (&undefp) +EXTERN int armsize; extern char* anames[]; extern Optab optab[]; @@ -292,104 +318,115 @@ EXTERN Prog* prog_modu; #pragma varargck type "A" int -#pragma varargck type "A" uint #pragma varargck type "C" int #pragma varargck type "D" Adr* +#pragma varargck type "I" uchar* #pragma varargck type "N" Adr* #pragma varargck type "P" Prog* #pragma varargck type "S" char* - -#pragma varargck argpos diag 1 +#pragma varargck type "Z" char* +#pragma varargck type "i" char* int Aconv(Fmt*); int Cconv(Fmt*); int Dconv(Fmt*); +int Iconv(Fmt*); int Nconv(Fmt*); +int Oconv(Fmt*); int Pconv(Fmt*); int Sconv(Fmt*); int aclass(Adr*); -void addhist(long, int); -void append(Prog*, Prog*); +void addhist(int32, int); +Prog* appendp(Prog*); void asmb(void); -void asmdyn(void); -void asmlc(void); -void asmout(Prog*, Optab*); -void asmsym(void); -long atolwhex(char*); +void asmout(Prog*, Optab*, int32*); +int32 atolwhex(char*); Prog* brloop(Prog*); void buildop(void); void buildrep(int, int); void cflush(void); -void ckoff(Sym*, long); +int chipzero(Ieee*); int chipfloat(Ieee*); int cmp(int, int); int compound(Prog*); double cputime(void); -void datblk(long, long, int); void diag(char*, ...); void divsig(void); void dodata(void); void doprof1(void); void doprof2(void); -void dynreloc(Sym*, long, int); -long entryvalue(void); -void errorexit(void); +int32 entryvalue(void); void exchange(Prog*); -void export(void); -int find1(long, int); void follow(void); -void gethunk(void); -void histtoauto(void); -double ieeedtod(Ieee*); -long ieeedtof(Ieee*); -void import(void); +void hputl(int); int isnop(Prog*); -void ldobj(int, long, char*); -void loadlib(void); void listinit(void); Sym* lookup(char*, int); void cput(int); -void lput(long); -void lputl(long); -void mkfwd(void); -void* mysbrk(ulong); +void hput(int32); +void lput(int32); +void lputb(int32); +void lputl(int32); +void* mysbrk(uint32); void names(void); void nocache(Prog*); -void nuxiinit(void); -void objfile(char*); int ocmp(const void*, const void*); -long opirr(int); +int32 opirr(int); Optab* oplook(Prog*); -long oprrr(int, int); -long olr(long, int, int, int); -long olhr(long, int, int, int); -long olrr(int, int, int, int); -long olhrr(int, int, int, int); -long osr(int, int, long, int, int); -long oshr(int, long, int, int); -long ofsr(int, int, long, int, int, Prog*); -long osrr(int, int, int, int); -long oshrr(int, int, int, int); -long omvl(Prog*, Adr*, int); +int32 oprrr(int, int); +int32 olr(int32, int, int, int); +int32 olhr(int32, int, int, int); +int32 olrr(int, int, int, int); +int32 olhrr(int, int, int, int); +int32 osr(int, int, int32, int, int); +int32 oshr(int, int32, int, int); +int32 ofsr(int, int, int32, int, int, Prog*); +int32 osrr(int, int, int, int); +int32 oshrr(int, int, int, int); +int32 omvl(Prog*, Adr*, int); void patch(void); void prasm(Prog*); void prepend(Prog*, Prog*); Prog* prg(void); int pseudo(Prog*); -void putsymb(char*, int, long, int); -void readundefs(char*, int); -long regoff(Adr*); +int32 regoff(Adr*); int relinv(int); -long rnd(long, long); +int32 rnd(int32, int32); +void softfloat(void); void span(void); void strnput(char*, int); +int32 symaddr(Sym*); void undef(void); -void undefsym(Sym*); -void wput(long); -void xdefine(char*, int, long); -void xfol(Prog*); -void zerosig(char*); +void wput(int32); +void wputl(ushort w); +void xdefine(char*, int, int32); void noops(void); -long immrot(ulong); -long immaddr(long); -long opbra(int, int); +int32 immrot(uint32); +int32 immaddr(int32); +int32 opbra(int, int); +int brextra(Prog*); +int isbranch(Prog*); +void fnptrs(void); +void doelf(void); + +vlong addaddr(Sym *s, Sym *t); +vlong addsize(Sym *s, Sym *t); +vlong addstring(Sym *s, char *str); +vlong adduint16(Sym *s, uint16 v); +vlong adduint32(Sym *s, uint32 v); +vlong adduint64(Sym *s, uint64 v); +vlong adduint8(Sym *s, uint8 v); +vlong adduintxx(Sym *s, uint64 v, int wid); + +/* Native is little-endian */ +#define LPUT(a) lputl(a) +#define WPUT(a) wputl(a) +#define VPUT(a) abort() + +#endif + +/* Used by ../ld/dwarf.c */ +enum +{ + DWARFREGSP = 4 +}; diff -r d8d00747375b sys/src/cmd/5l/l.s --- a/sys/src/cmd/5l/l.s Thu Sep 29 03:00:00 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -TEXT main(SB), $0 - - ADD R1,R4 - ADD R1,R3,R4 - ADD R1<<1,R3,R4 /* logical left */ - ADD R1>>1,R3,R4 /* logical right */ - ADD R1->1,R3,R4 /* arithmetic right */ - ADD R1@>1,R3,R4 /* rotate right */ - - ADD R1<as; switch(a) { default: - s = str; - s += sprint(s, "(%ld)", p->line); + fmtprint(fp, "(%d)", p->line); if(p->reg == NREG) - sprint(s, " %A%C %D,%D", + fmtprint(fp, " %A%C %D,%D", a, p->scond, &p->from, &p->to); else if(p->from.type != D_FREG) - sprint(s, " %A%C %D,R%d,%D", + fmtprint(fp, " %A%C %D,R%d,%D", a, p->scond, &p->from, p->reg, &p->to); else - sprint(s, " %A%C %D,F%d,%D", + fmtprint(fp, " %A%C %D,F%d,%D", a, p->scond, &p->from, p->reg, &p->to); break; case ASWPW: case ASWPBU: - sprint(str, "(%ld) %A%C R%d,%D,%D", + fmtprint(fp, "(%d) %A%C R%d,%D,%D", p->line, a, p->scond, p->reg, &p->from, &p->to); break; case ADATA: - case AINIT: - case ADYNT: - sprint(str, "(%ld) %A%C %D/%d,%D", + case AINIT_: + case ADYNT_: + fmtprint(fp, "(%d) %A%C %D/%d,%D", p->line, a, p->scond, &p->from, p->reg, &p->to); break; + + case AWORD: + fmtprint(fp, "(%d) WORD %D", p->line, &p->to); + break; + + case ADWORD: + fmtprint(fp, "(%d) DWORD %D %D", p->line, &p->from, &p->to); + break; } - return fmtstrcpy(fp, str); + + if(p->spadj) + fmtprint(fp, " (spadj%+d)", p->spadj); + + return 0; } int @@ -118,100 +163,104 @@ char str[STRINGSZ]; char *op; Adr *a; - long v; + int32 v; a = va_arg(fp->args, Adr*); switch(a->type) { default: - sprint(str, "GOK-type(%d)", a->type); + snprint(str, sizeof str, "GOK-type(%d)", a->type); break; case D_NONE: str[0] = 0; if(a->name != D_NONE || a->reg != NREG || a->sym != S) - sprint(str, "%N(R%d)(NONE)", a, a->reg); + snprint(str, sizeof str, "%N(R%d)(NONE)", a, a->reg); break; case D_CONST: if(a->reg == NREG) - sprint(str, "$%N", a); + snprint(str, sizeof str, "$%N", a); else - sprint(str, "$%N(R%d)", a, a->reg); + snprint(str, sizeof str, "$%N(R%d)", a, a->reg); + break; + + case D_CONST2: + snprint(str, sizeof str, "$%d-%d", a->offset, a->offset2); break; case D_SHIFT: v = a->offset; op = "<<>>->@>" + (((v>>5) & 3) << 1); if(v & (1<<4)) - sprint(str, "R%ld%c%cR%ld", v&15, op[0], op[1], (v>>8)&15); + snprint(str, sizeof str, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15); else - sprint(str, "R%ld%c%c%ld", v&15, op[0], op[1], (v>>7)&31); + snprint(str, sizeof str, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31); if(a->reg != NREG) - sprint(str+strlen(str), "(R%d)", a->reg); + seprint(str+strlen(str), str+sizeof str, "(R%d)", a->reg); break; case D_OCONST: - sprint(str, "$*$%N", a); + snprint(str, sizeof str, "$*$%N", a); if(a->reg != NREG) - sprint(str, "%N(R%d)(CONST)", a, a->reg); + snprint(str, sizeof str, "%N(R%d)(CONST)", a, a->reg); break; case D_OREG: if(a->reg != NREG) - sprint(str, "%N(R%d)", a, a->reg); + snprint(str, sizeof str, "%N(R%d)", a, a->reg); else - sprint(str, "%N", a); + snprint(str, sizeof str, "%N", a); break; case D_REG: - sprint(str, "R%d", a->reg); + snprint(str, sizeof str, "R%d", a->reg); if(a->name != D_NONE || a->sym != S) - sprint(str, "%N(R%d)(REG)", a, a->reg); + snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg); break; case D_REGREG: - sprint(str, "(R%d,R%d)", a->reg, (int)a->offset); + snprint(str, sizeof str, "(R%d,R%d)", a->reg, (int)a->offset); if(a->name != D_NONE || a->sym != S) - sprint(str, "%N(R%d)(REG)", a, a->reg); + snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg); break; case D_FREG: - sprint(str, "F%d", a->reg); + snprint(str, sizeof str, "F%d", a->reg); if(a->name != D_NONE || a->sym != S) - sprint(str, "%N(R%d)(REG)", a, a->reg); + snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg); break; case D_PSR: switch(a->reg) { case 0: - sprint(str, "CPSR"); + snprint(str, sizeof str, "CPSR"); break; case 1: - sprint(str, "SPSR"); + snprint(str, sizeof str, "SPSR"); break; default: - sprint(str, "PSR%d", a->reg); + snprint(str, sizeof str, "PSR%d", a->reg); break; } if(a->name != D_NONE || a->sym != S) - sprint(str, "%N(PSR%d)(REG)", a, a->reg); + snprint(str, sizeof str, "%N(PSR%d)(REG)", a, a->reg); break; case D_FPCR: switch(a->reg){ case 0: - sprint(str, "FPSR"); + snprint(str, sizeof str, "FPSR"); break; case 1: - sprint(str, "FPCR"); + snprint(str, sizeof str, "FPCR"); break; default: - sprint(str, "FCR%d", a->reg); + snprint(str, sizeof str, "FCR%d", a->reg); break; } if(a->name != D_NONE || a->sym != S) - sprint(str, "%N(FCR%d)(REG)", a, a->reg); + snprint(str, sizeof str, "%N(FCR%d)(REG)", a, a->reg); break; @@ -219,22 +268,22 @@ if(curp->cond != P) { v = curp->cond->pc; if(a->sym != S) - sprint(str, "%s+%.5lux(BRANCH)", a->sym->name, v); + snprint(str, sizeof str, "%s+%.5ux(BRANCH)", a->sym->name, v); else - sprint(str, "%.5lux(BRANCH)", v); + snprint(str, sizeof str, "%.5ux(BRANCH)", v); } else if(a->sym != S) - sprint(str, "%s+%ld(APC)", a->sym->name, a->offset); + snprint(str, sizeof str, "%s+%d(APC)", a->sym->name, a->offset); else - sprint(str, "%ld(APC)", a->offset); + snprint(str, sizeof str, "%d(APC)", a->offset); break; case D_FCONST: - sprint(str, "$%e", ieeedtod(a->ieee)); + snprint(str, sizeof str, "$%e", ieeedtod(&a->ieee)); break; case D_SCONST: - sprint(str, "$\"%S\"", a->sval); + snprint(str, sizeof str, "$\"%S\"", a->sval); break; } return fmtstrcpy(fp, str); @@ -255,35 +304,35 @@ break; case D_NONE: - sprint(str, "%ld", a->offset); + sprint(str, "%d", a->offset); break; case D_EXTERN: if(s == S) - sprint(str, "%ld(SB)", a->offset); + sprint(str, "%d(SB)", a->offset); else - sprint(str, "%s+%ld(SB)", s->name, a->offset); + sprint(str, "%s+%d(SB)", s->name, a->offset); break; case D_STATIC: if(s == S) - sprint(str, "<>+%ld(SB)", a->offset); + sprint(str, "<>+%d(SB)", a->offset); else - sprint(str, "%s<>+%ld(SB)", s->name, a->offset); + sprint(str, "%s<>+%d(SB)", s->name, a->offset); break; case D_AUTO: if(s == S) - sprint(str, "%ld(SP)", a->offset); + sprint(str, "%d(SP)", a->offset); else - sprint(str, "%s-%ld(SP)", s->name, -a->offset); + sprint(str, "%s-%d(SP)", s->name, -a->offset); break; case D_PARAM: if(s == S) - sprint(str, "%ld(FP)", a->offset); + sprint(str, "%d(FP)", a->offset); else - sprint(str, "%s+%ld(FP)", s->name, a->offset); + sprint(str, "%s+%d(FP)", s->name, a->offset); break; } return fmtstrcpy(fp, str); @@ -297,7 +346,7 @@ a = va_arg(fp->args, char*); p = str; - for(i=0; i= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || @@ -330,22 +379,108 @@ return fmtstrcpy(fp, str); } +int +Iconv(Fmt *fp) +{ + int i, n; + uint32 *p; + char *s; + Fmt fmt; + + n = fp->prec; + fp->prec = 0; + if(!(fp->flags&FmtPrec) || n < 0) + return fmtstrcpy(fp, "%I"); + fp->flags &= ~FmtPrec; + p = va_arg(fp->args, uint32*); + + // format into temporary buffer and + // call fmtstrcpy to handle padding. + fmtstrinit(&fmt); + for(i=0; i 0) + fmtprint(&fmt, " "); + fmtprint(&fmt, "%.8ux", *p++); + } + s = fmtstrflush(&fmt); + fmtstrcpy(fp, s); + free(s); + return 0; +} + +static char* +cnames[] = +{ + [C_ADDR] = "C_ADDR", + [C_FAUTO] = "C_FAUTO", + [C_ZFCON] = "C_SFCON", + [C_SFCON] = "C_SFCON", + [C_LFCON] = "C_LFCON", + [C_FCR] = "C_FCR", + [C_FOREG] = "C_FOREG", + [C_FREG] = "C_FREG", + [C_GOK] = "C_GOK", + [C_HAUTO] = "C_HAUTO", + [C_HFAUTO] = "C_HFAUTO", + [C_HFOREG] = "C_HFOREG", + [C_HOREG] = "C_HOREG", + [C_HREG] = "C_HREG", + [C_LACON] = "C_LACON", + [C_LAUTO] = "C_LAUTO", + [C_LBRA] = "C_LBRA", + [C_LCON] = "C_LCON", + [C_LOREG] = "C_LOREG", + [C_NCON] = "C_NCON", + [C_NONE] = "C_NONE", + [C_PC] = "C_PC", + [C_PSR] = "C_PSR", + [C_RACON] = "C_RACON", + [C_RCON] = "C_RCON", + [C_REG] = "C_REG", + [C_REGREG] = "C_REGREG", + [C_ROREG] = "C_ROREG", + [C_SAUTO] = "C_SAUTO", + [C_SBRA] = "C_SBRA", + [C_SCON] = "C_SCON", + [C_SHIFT] = "C_SHIFT", + [C_SOREG] = "C_SOREG", + [C_SP] = "C_SP", + [C_SROREG] = "C_SROREG" +}; + +int +Oconv(Fmt *fp) +{ + char buf[500]; + int o; + + o = va_arg(fp->args, int); + if(o < 0 || o >= nelem(cnames) || cnames[o] == nil) { + snprint(buf, sizeof(buf), "C_%d", o); + return fmtstrcpy(fp, buf); + } + return fmtstrcpy(fp, cnames[o]); +} + void diag(char *fmt, ...) { - char buf[STRINGSZ], *tn; + char buf[STRINGSZ], *tn, *sep; va_list arg; - tn = "??none??"; - if(curtext != P && curtext->from.sym != S) - tn = curtext->from.sym->name; + tn = ""; + sep = ""; + if(cursym != S) { + tn = cursym->name; + sep = ": "; + } va_start(arg, fmt); vseprint(buf, buf+sizeof(buf), fmt, arg); va_end(arg); - print("%s: %s\n", tn, buf); + print("%s%s%s\n", tn, sep, buf); nerrors++; - if(nerrors > 10) { + if(nerrors > 20) { print("too many errors\n"); errorexit(); } diff -r d8d00747375b sys/src/cmd/5l/mkenam --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/src/cmd/5l/mkenam Mon Nov 14 17:35:25 2011 +0100 @@ -0,0 +1,45 @@ +# Inferno utils/5c/mkenam +# http://code.google.com/p/inferno-os/source/browse/utils/5c/mkenam +# +# 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. + +awk ' +BEGIN { + print "char* anames[] =" + print "{" +} + +/^ A/ { + name=$1 + sub(/,/, "", name) + sub(/^A/, "", name) + print "\t\"" name "\"," +} + +END { print "};" } +' ../5l/5.out.h >enam.c diff -r d8d00747375b sys/src/cmd/5l/mkfile --- a/sys/src/cmd/5l/mkfile Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/5l/mkfile Mon Nov 14 17:35:25 2011 +0100 @@ -3,24 +3,45 @@ TARG=5l OFILES=\ asm.$O\ + data.$O\ + dwarf.$O\ + elf.$O\ + enam.$O\ + go.$O\ + ldelf.$O\ + ldmacho.$O\ + ldpe.$O\ + lib.$O\ list.$O\ + macho.$O\ noop.$O\ obj.$O\ optab.$O\ pass.$O\ + pe.$O\ + prof.$O\ span.$O\ - enam.$O\ - compat.$O\ + symtab.$O\ + softfloat.$O\ HFILES=\ l.h\ - ../5c/5.out.h\ + 5.out.h\ + ../ld/dwarf.h\ + ../ld/elf.h\ + ../ld/lib.h\ + ../ld/macho.h\ + ../ld/pe.h\ BIN=/$objtype/bin type != STEXT) { + diag("runtime·morestack not defined"); + errorexit(); + } + pmorestack = symmorestack->text; + pmorestack->reg |= NOSPLIT; q = P; - for(p = firstp; p != P; p = p->link) { - - /* find out how much arg space is used in this TEXT */ - if(p->to.type == D_OREG && p->to.reg == REGSP) - if(p->to.offset > curframe) - curframe = p->to.offset; - - switch(p->as) { - case ATEXT: - if(curtext && curtext->from.sym) { - curtext->from.sym->frame = curframe; - curtext->from.sym->become = curbecome; - if(curbecome > maxbecome) - maxbecome = curbecome; - } - curframe = 0; - curbecome = 0; - - p->mark |= LEAF; - curtext = p; - break; - - case ARET: - /* special form of RET is BECOME */ - if(p->from.type == D_CONST) - if(p->from.offset > curbecome) - curbecome = p->from.offset; - break; - - case ADIV: - case ADIVU: - case AMOD: - case AMODU: - q = p; - if(prog_div == P) - initdiv(); - if(curtext != P) - curtext->mark &= ~LEAF; - continue; - - case ANOP: - q1 = p->link; - q->link = q1; /* q is non-nop */ - q1->mark |= p->mark; - continue; - - case ABL: - if(curtext != P) - curtext->mark &= ~LEAF; - - case ABCASE: - case AB: - - case ABEQ: - case ABNE: - case ABCS: - case ABHS: - case ABCC: - case ABLO: - case ABMI: - case ABPL: - case ABVS: - case ABVC: - case ABHI: - case ABLS: - case ABGE: - case ABLT: - case ABGT: - case ABLE: - - q1 = p->cond; - if(q1 != P) { - while(q1->as == ANOP) { - q1 = q1->link; - p->cond = q1; - } - } - break; - } - q = p; - } - - if(curtext && curtext->from.sym) { - curtext->from.sym->frame = curframe; - curtext->from.sym->become = curbecome; - if(curbecome > maxbecome) - maxbecome = curbecome; - } - - if(debug['b']) - print("max become = %d\n", maxbecome); - xdefine("ALEFbecome", STEXT, maxbecome); - - curtext = 0; - for(p = firstp; p != P; p = p->link) { - switch(p->as) { - case ATEXT: - curtext = p; - break; - case ABL: - if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) { - o = maxbecome - curtext->from.sym->frame; - if(o <= 0) - break; - /* calling a become or calling a variable */ - if(p->to.sym == S || p->to.sym->become) { - curtext->to.offset += o; - if(debug['b']) { - curp = p; - print("%D calling %D increase %d\n", - &curtext->from, &p->to, o); + for(cursym = textp; cursym != nil; cursym = cursym->next) { + for(p = cursym->text; p != P; p = p->link) { + switch(p->as) { + case ATEXT: + p->mark |= LEAF; + break; + + case ARET: + break; + + case ADIV: + case ADIVU: + case AMOD: + case AMODU: + q = p; + if(prog_div == P) + initdiv(); + cursym->text->mark &= ~LEAF; + continue; + + case ANOP: + q1 = p->link; + q->link = q1; /* q is non-nop */ + if(q1 != P) + q1->mark |= p->mark; + continue; + + case ABL: + case ABX: + cursym->text->mark &= ~LEAF; + + case ABCASE: + case AB: + + case ABEQ: + case ABNE: + case ABCS: + case ABHS: + case ABCC: + case ABLO: + case ABMI: + case ABPL: + case ABVS: + case ABVC: + case ABHI: + case ABLS: + case ABGE: + case ABLT: + case ABGT: + case ABLE: + q1 = p->cond; + if(q1 != P) { + while(q1->as == ANOP) { + q1 = q1->link; + p->cond = q1; } } + break; } - break; + q = p; } } - for(p = firstp; p != P; p = p->link) { - o = p->as; - switch(o) { - case ATEXT: - curtext = p; - autosize = p->to.offset + 4; - if(autosize <= 4) - if(curtext->mark & LEAF) { - p->to.offset = -4; - autosize = 0; - } + for(cursym = textp; cursym != nil; cursym = cursym->next) { + for(p = cursym->text; p != P; p = p->link) { + o = p->as; + switch(o) { + case ATEXT: + autosize = p->to.offset + 4; + if(autosize <= 4) + if(cursym->text->mark & LEAF) { + p->to.offset = -4; + autosize = 0; + } + + if(!autosize && !(cursym->text->mark & LEAF)) { + if(debug['v']) + Bprint(&bso, "save suppressed in: %s\n", + cursym->name); + Bflush(&bso); + cursym->text->mark |= LEAF; + } + if(cursym->text->mark & LEAF) { + cursym->leaf = 1; + if(!autosize) + break; + } + + if(p->reg & NOSPLIT) { + q1 = prg(); + q1->as = AMOVW; + q1->scond |= C_WBIT; + q1->line = p->line; + q1->from.type = D_REG; + q1->from.reg = REGLINK; + q1->to.type = D_OREG; + q1->to.offset = -autosize; + q1->to.reg = REGSP; + q1->spadj = autosize; + q1->link = p->link; + p->link = q1; + } else if (autosize < StackBig) { + // split stack check for small functions + // MOVW g_stackguard(g), R1 + // CMP R1, $-autosize(SP) + // MOVW.LO $autosize, R1 + // MOVW.LO $args, R2 + // MOVW.LO R14, R3 + // BL.LO runtime.morestack(SB) // modifies LR + // MOVW.W R14,$-autosize(SP) + + // TODO(kaib): add more trampolines + // TODO(kaib): put stackguard in register + // TODO(kaib): add support for -K and underflow detection - if(!autosize && !(curtext->mark & LEAF)) { - if(debug['v']) - Bprint(&bso, "save suppressed in: %s\n", - curtext->from.sym->name); - Bflush(&bso); - curtext->mark |= LEAF; - } + // MOVW g_stackguard(g), R1 + p = appendp(p); + p->as = AMOVW; + p->from.type = D_OREG; + p->from.reg = REGG; + p->to.type = D_REG; + p->to.reg = 1; + + if(autosize < StackSmall) { + // CMP R1, SP + p = appendp(p); + p->as = ACMP; + p->from.type = D_REG; + p->from.reg = 1; + p->reg = REGSP; + } else { + // MOVW $-autosize(SP), R2 + // CMP R1, R2 + p = appendp(p); + p->as = AMOVW; + p->from.type = D_CONST; + p->from.reg = REGSP; + p->from.offset = -autosize; + p->to.type = D_REG; + p->to.reg = 2; + + p = appendp(p); + p->as = ACMP; + p->from.type = D_REG; + p->from.reg = 1; + p->reg = 2; + } - if(curtext->mark & LEAF) { - if(curtext->from.sym) - curtext->from.sym->type = SLEAF; -#ifdef optimise_time - if(autosize) { - q = prg(); - q->as = ASUB; - q->line = p->line; - q->from.type = D_CONST; - q->from.offset = autosize; - q->to.type = D_REG; - q->to.reg = REGSP; - - q->link = p->link; - p->link = q; + // MOVW.LO $autosize, R1 + p = appendp(p); + p->as = AMOVW; + p->scond = C_SCOND_LO; + p->from.type = D_CONST; + /* 160 comes from 3 calls (3*8) 4 safes (4*8) and 104 guard */ + p->from.offset = autosize+160; + p->to.type = D_REG; + p->to.reg = 1; + + // MOVW.LO $args, R2 + p = appendp(p); + p->as = AMOVW; + p->scond = C_SCOND_LO; + p->from.type = D_CONST; + p->from.offset = (cursym->text->to.offset2 + 3) & ~3; + p->to.type = D_REG; + p->to.reg = 2; + + // MOVW.LO R14, R3 + p = appendp(p); + p->as = AMOVW; + p->scond = C_SCOND_LO; + p->from.type = D_REG; + p->from.reg = REGLINK; + p->to.type = D_REG; + p->to.reg = 3; + + // BL.LO runtime.morestack(SB) // modifies LR + p = appendp(p); + p->as = ABL; + p->scond = C_SCOND_LO; + p->to.type = D_BRANCH; + p->to.sym = symmorestack; + p->cond = pmorestack; + + // MOVW.W R14,$-autosize(SP) + p = appendp(p); + p->as = AMOVW; + p->scond |= C_WBIT; + p->from.type = D_REG; + p->from.reg = REGLINK; + p->to.type = D_OREG; + p->to.offset = -autosize; + p->to.reg = REGSP; + p->spadj = autosize; + } else { // > StackBig + // MOVW $autosize, R1 + // MOVW $args, R2 + // MOVW R14, R3 + // BL runtime.morestack(SB) // modifies LR + // MOVW.W R14,$-autosize(SP) + + // MOVW $autosize, R1 + p = appendp(p); + p->as = AMOVW; + p->from.type = D_CONST; + p->from.offset = autosize; + p->to.type = D_REG; + p->to.reg = 1; + + // MOVW $args, R2 + // also need to store the extra 4 bytes. + p = appendp(p); + p->as = AMOVW; + p->from.type = D_CONST; + p->from.offset = (cursym->text->to.offset2 + 3) & ~3; + p->to.type = D_REG; + p->to.reg = 2; + + // MOVW R14, R3 + p = appendp(p); + p->as = AMOVW; + p->from.type = D_REG; + p->from.reg = REGLINK; + p->to.type = D_REG; + p->to.reg = 3; + + // BL runtime.morestack(SB) // modifies LR + p = appendp(p); + p->as = ABL; + p->to.type = D_BRANCH; + p->to.sym = symmorestack; + p->cond = pmorestack; + + // MOVW.W R14,$-autosize(SP) + p = appendp(p); + p->as = AMOVW; + p->scond |= C_WBIT; + p->from.type = D_REG; + p->from.reg = REGLINK; + p->to.type = D_OREG; + p->to.offset = -autosize; + p->to.reg = REGSP; + p->spadj = autosize; } break; -#else - if(!autosize) + + case ARET: + nocache(p); + if(cursym->text->mark & LEAF) { + if(!autosize) { + p->as = AB; + p->from = zprg.from; + p->to.type = D_OREG; + p->to.offset = 0; + p->to.reg = REGLINK; + break; + } + } + p->as = AMOVW; + p->scond |= C_PBIT; + p->from.type = D_OREG; + p->from.offset = autosize; + p->from.reg = REGSP; + p->to.type = D_REG; + p->to.reg = REGPC; + // If there are instructions following + // this ARET, they come from a branch + // with the same stackframe, so no spadj. + break; + + case AADD: + if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP) + p->spadj = -p->from.offset; + break; + + case ASUB: + if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP) + p->spadj = p->from.offset; + break; + + case ADIV: + case ADIVU: + case AMOD: + case AMODU: + if(debug['M']) break; -#endif - } - - q1 = prg(); - q1->as = AMOVW; - q1->scond |= C_WBIT; - q1->line = p->line; - q1->from.type = D_REG; - q1->from.reg = REGLINK; - q1->to.type = D_OREG; - q1->to.offset = -autosize; - q1->to.reg = REGSP; - - q1->link = p->link; - p->link = q1; - break; - - case ARET: - nocache(p); - if(p->from.type == D_CONST) - goto become; - if(curtext->mark & LEAF) { - if(!autosize) { - p->as = AB; - p->from = zprg.from; - p->to.type = D_OREG; - p->to.offset = 0; - p->to.reg = REGLINK; + if(p->from.type != D_REG) + break; + if(p->to.type != D_REG) + break; + q1 = p; + + /* MOV a,4(SP) */ + q = prg(); + q->link = p->link; + p->link = q; + p = q; + + p->as = AMOVW; + p->line = q1->line; + p->from.type = D_REG; + p->from.reg = q1->from.reg; + p->to.type = D_OREG; + p->to.reg = REGSP; + p->to.offset = 4; + + /* MOV b,REGTMP */ + q = prg(); + q->link = p->link; + p->link = q; + p = q; + + p->as = AMOVW; + p->line = q1->line; + p->from.type = D_REG; + p->from.reg = q1->reg; + if(q1->reg == NREG) + p->from.reg = q1->to.reg; + p->to.type = D_REG; + p->to.reg = REGTMP; + p->to.offset = 0; + + /* CALL appropriate */ + q = prg(); + q->link = p->link; + p->link = q; + p = q; + + p->as = ABL; + p->line = q1->line; + p->to.type = D_BRANCH; + p->cond = p; + switch(o) { + case ADIV: + p->cond = prog_div; + p->to.sym = sym_div; + break; + case ADIVU: + p->cond = prog_divu; + p->to.sym = sym_divu; + break; + case AMOD: + p->cond = prog_mod; + p->to.sym = sym_mod; + break; + case AMODU: + p->cond = prog_modu; + p->to.sym = sym_modu; break; } - -#ifdef optimise_time + + /* MOV REGTMP, b */ + q = prg(); + q->link = p->link; + p->link = q; + p = q; + + p->as = AMOVW; + p->line = q1->line; + p->from.type = D_REG; + p->from.reg = REGTMP; + p->from.offset = 0; + p->to.type = D_REG; + p->to.reg = q1->to.reg; + + /* ADD $8,SP */ + q = prg(); + q->link = p->link; + p->link = q; + p = q; + p->as = AADD; p->from.type = D_CONST; - p->from.offset = autosize; + p->from.reg = NREG; + p->from.offset = 8; + p->reg = NREG; p->to.type = D_REG; p->to.reg = REGSP; - - q = prg(); - q->as = AB; - q->scond = p->scond; - q->line = p->line; - q->to.type = D_OREG; - q->to.offset = 0; - q->to.reg = REGLINK; - - q->link = p->link; - p->link = q; - + p->spadj = -8; + + /* SUB $8,SP */ + q1->as = ASUB; + q1->from.type = D_CONST; + q1->from.offset = 8; + q1->from.reg = NREG; + q1->reg = NREG; + q1->to.type = D_REG; + q1->to.reg = REGSP; + q1->spadj = 8; + break; -#endif - } - p->as = AMOVW; - p->scond |= C_PBIT; - p->from.type = D_OREG; - p->from.offset = autosize; - p->from.reg = REGSP; - p->to.type = D_REG; - p->to.reg = REGPC; - break; - - become: - if(curtext->mark & LEAF) { - - if(!autosize) { - p->as = AB; - p->from = zprg.from; - break; - } - -#ifdef optimise_time - q = prg(); - q->scond = p->scond; - q->line = p->line; - q->as = AB; - q->from = zprg.from; - q->to = p->to; - q->cond = p->cond; - q->link = p->link; - p->link = q; - - p->as = AADD; - p->from = zprg.from; - p->from.type = D_CONST; - p->from.offset = autosize; - p->to = zprg.to; - p->to.type = D_REG; - p->to.reg = REGSP; - - break; -#endif - } - q = prg(); - q->scond = p->scond; - q->line = p->line; - q->as = AB; - q->from = zprg.from; - q->to = p->to; - q->cond = p->cond; - q->link = p->link; - p->link = q; - - p->as = AMOVW; - p->scond |= C_PBIT; - p->from = zprg.from; - p->from.type = D_OREG; - p->from.offset = autosize; - p->from.reg = REGSP; - p->to = zprg.to; - p->to.type = D_REG; - p->to.reg = REGLINK; - - break; - - case ADIV: - case ADIVU: - case AMOD: - case AMODU: - if(debug['M']) - break; - if(p->from.type != D_REG) - break; - if(p->to.type != D_REG) - break; - q1 = p; - - /* MOV a,4(SP) */ - q = prg(); - q->link = p->link; - p->link = q; - p = q; - - p->as = AMOVW; - p->line = q1->line; - p->from.type = D_REG; - p->from.reg = q1->from.reg; - p->to.type = D_OREG; - p->to.reg = REGSP; - p->to.offset = 4; - - /* MOV b,REGTMP */ - q = prg(); - q->link = p->link; - p->link = q; - p = q; - - p->as = AMOVW; - p->line = q1->line; - p->from.type = D_REG; - p->from.reg = q1->reg; - if(q1->reg == NREG) - p->from.reg = q1->to.reg; - p->to.type = D_REG; - p->to.reg = REGTMP; - p->to.offset = 0; - - /* CALL appropriate */ - q = prg(); - q->link = p->link; - p->link = q; - p = q; - - p->as = ABL; - p->line = q1->line; - p->to.type = D_BRANCH; - p->cond = p; - switch(o) { - case ADIV: - p->cond = prog_div; - p->to.sym = sym_div; - break; - case ADIVU: - p->cond = prog_divu; - p->to.sym = sym_divu; - break; - case AMOD: - p->cond = prog_mod; - p->to.sym = sym_mod; - break; - case AMODU: - p->cond = prog_modu; - p->to.sym = sym_modu; + case AMOVW: + if((p->scond & C_WBIT) && p->to.type == D_OREG && p->to.reg == REGSP) + p->spadj = -p->to.offset; + if((p->scond & C_PBIT) && p->from.type == D_OREG && p->from.reg == REGSP && p->to.reg != REGPC) + p->spadj = -p->from.offset; + if(p->from.type == D_CONST && p->from.reg == REGSP && p->to.type == D_REG && p->to.reg == REGSP) + p->spadj = -p->from.offset; break; } - - /* MOV REGTMP, b */ - q = prg(); - q->link = p->link; - p->link = q; - p = q; - - p->as = AMOVW; - p->line = q1->line; - p->from.type = D_REG; - p->from.reg = REGTMP; - p->from.offset = 0; - p->to.type = D_REG; - p->to.reg = q1->to.reg; - - /* ADD $8,SP */ - q = prg(); - q->link = p->link; - p->link = q; - p = q; - - p->as = AADD; - p->from.type = D_CONST; - p->from.reg = NREG; - p->from.offset = 8; - p->reg = NREG; - p->to.type = D_REG; - p->to.reg = REGSP; - - /* SUB $8,SP */ - q1->as = ASUB; - q1->from.type = D_CONST; - q1->from.offset = 8; - q1->from.reg = NREG; - q1->reg = NREG; - q1->to.type = D_REG; - q1->to.reg = REGSP; - break; } } } @@ -420,12 +483,9 @@ Sym *s; s = lookup(n, 0); - if(s->type == STEXT){ + if(s->type == STEXT) if(s->sig == 0) s->sig = SIGNINTERN; - } - else if(s->type == 0 || s->type == SXREF) - s->type = SUNDEF; } void @@ -437,25 +497,10 @@ sigdiv("_modu"); } -static void -sdiv(Sym *s) -{ - if(s->type == 0 || s->type == SXREF){ - /* undefsym(s); */ - s->type = SXREF; - if(s->sig == 0) - s->sig = SIGNINTERN; - s->subtype = SIMPORT; - } - else if(s->type != STEXT) - diag("undefined: %s", s->name); -} - void initdiv(void) { Sym *s2, *s3, *s4, *s5; - Prog *p; if(prog_div != P) return; @@ -463,38 +508,25 @@ sym_divu = s3 = lookup("_divu", 0); sym_mod = s4 = lookup("_mod", 0); sym_modu = s5 = lookup("_modu", 0); - if(dlm) { - sdiv(s2); if(s2->type == SXREF) prog_div = UP; - sdiv(s3); if(s3->type == SXREF) prog_divu = UP; - sdiv(s4); if(s4->type == SXREF) prog_mod = UP; - sdiv(s5); if(s5->type == SXREF) prog_modu = UP; - } - for(p = firstp; p != P; p = p->link) - if(p->as == ATEXT) { - if(p->from.sym == s2) - prog_div = p; - if(p->from.sym == s3) - prog_divu = p; - if(p->from.sym == s4) - prog_mod = p; - if(p->from.sym == s5) - prog_modu = p; - } + prog_div = s2->text; + prog_divu = s3->text; + prog_mod = s4->text; + prog_modu = s5->text; if(prog_div == P) { diag("undefined: %s", s2->name); - prog_div = curtext; + prog_div = cursym->text; } if(prog_divu == P) { diag("undefined: %s", s3->name); - prog_divu = curtext; + prog_divu = cursym->text; } if(prog_mod == P) { diag("undefined: %s", s4->name); - prog_mod = curtext; + prog_mod = cursym->text; } if(prog_modu == P) { diag("undefined: %s", s5->name); - prog_modu = curtext; + prog_modu = cursym->text; } } diff -r d8d00747375b sys/src/cmd/5l/obj.c --- a/sys/src/cmd/5l/obj.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/5l/obj.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,5 +1,39 @@ +// Inferno utils/5l/obj.c +// http://code.google.com/p/inferno-os/source/browse/utils/5l/obj.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. + +// Reading object files. + #define EXTERN #include "l.h" +#include "../ld/lib.h" +#include "../ld/elf.h" #include #ifndef DEFAULT @@ -7,126 +41,117 @@ #endif char *noname = ""; -char symname[] = SYMDEF; -char thechar = '5'; char *thestring = "arm"; +Header headers[] = { + "noheader", Hnoheader, + "risc", Hrisc, + "plan9", Hplan9x32, + "netbsd", Hnetbsd, + "ixp1200", Hixp1200, + "ipaq", Hipaq, + "linux", Hlinux, + 0, 0 +}; + /* - * -H1 -T0x10005000 -R4 is aif for risc os - * -H2 -T4128 -R4096 is plan9 format - * -H3 -T0xF0000020 -R4 is NetBSD format - * -H4 is IXP1200 (raw) - * -H5 -T0xC0008010 -R1024 is ipaq + * -Hrisc -T0x10005000 -R4 is aif for risc os + * -Hplan9 -T4128 -R4096 is plan9 format + * -Hnetbsd -T0xF0000020 -R4 is NetBSD format + * -Hixp1200 is IXP1200 (raw) + * -Hipaq -T0xC0008010 -R1024 is ipaq + * -Hlinux -Tx -Rx is linux elf */ -static int -isobjfile(char *f) +static char* +linkername[] = { - int n, v; - Biobuf *b; - char buf1[5], buf2[SARMAG]; + "runtime.softfloat", + "math.sqrtGoC", +}; - 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 +usage(void) +{ + fprint(2, "usage: 5l [-E entry] [-H head] [-I interpreter] [-L dir] [-T text] [-D data] [-R rnd] [-r path] [-o out] main.5\n"); + errorexit(); } void main(int argc, char *argv[]) { - int c; - char *a; + int c, i; + char *p; Binit(&bso, 1, OWRITE); - cout = -1; listinit(); - outfile = 0; nerrors = 0; - curtext = P; + outfile = "5.out"; HEADTYPE = -1; INITTEXT = -1; INITDAT = -1; INITRND = -1; INITENTRY = 0; + + p = getenv("GOARM"); + if(p != nil && strcmp(p, "5") == 0) + debug['F'] = 1; ARGBEGIN { default: c = ARGC(); - if(c >= 0 && c < sizeof(debug)) + if(c == 'l') + usage(); + if(c >= 0 && c < sizeof(debug)) debug[c]++; break; case 'o': - outfile = ARGF(); + outfile = EARGF(usage()); break; case 'E': - a = ARGF(); - if(a) - INITENTRY = a; + INITENTRY = EARGF(usage()); + break; + case 'I': + interpreter = EARGF(usage()); + break; + case 'L': + Lflag(EARGF(usage())); break; case 'T': - a = ARGF(); - if(a) - INITTEXT = atolwhex(a); + INITTEXT = atolwhex(EARGF(usage())); break; case 'D': - a = ARGF(); - if(a) - INITDAT = atolwhex(a); + INITDAT = atolwhex(EARGF(usage())); break; case 'R': - a = ARGF(); - if(a) - INITRND = atolwhex(a); + INITRND = atolwhex(EARGF(usage())); + break; + case 'r': + rpath = EARGF(usage()); break; case 'H': - a = ARGF(); - if(a) - HEADTYPE = atolwhex(a); + HEADTYPE = headtype(EARGF(usage())); /* do something about setting INITTEXT */ break; - case 'x': /* produce export table */ - doexp = 1; - if(argv[1] != nil && argv[1][0] != '-' && !isobjfile(argv[1])) - readundefs(ARGF(), SEXPORT); - break; - case 'u': /* produce dynamically loadable module */ - dlm = 1; - if(argv[1] != nil && argv[1][0] != '-' && !isobjfile(argv[1])) - readundefs(ARGF(), SIMPORT); - break; + case 'V': + print("%cl version %s\n", thechar, getgoversion()); + errorexit(); } ARGEND USED(argc); - if(*argv == 0) { - diag("usage: 5l [-options] objects"); - errorexit(); - } - if(!debug['9'] && !debug['U'] && !debug['B']) - debug[DEFAULT] = 1; - if(HEADTYPE == -1) { - if(debug['U']) - HEADTYPE = 0; - if(debug['B']) - HEADTYPE = 1; - if(debug['9']) - HEADTYPE = 2; - } + if(argc != 1) + usage(); + + libinit(); + + if(HEADTYPE == -1) + HEADTYPE = Hlinux; switch(HEADTYPE) { default: diag("unknown -H option"); errorexit(); - case 0: /* no header */ + case Hnoheader: /* no header */ HEADR = 0L; if(INITTEXT == -1) INITTEXT = 0; @@ -135,7 +160,7 @@ if(INITRND == -1) INITRND = 4; break; - case 1: /* aif for risc os */ + case Hrisc: /* aif for risc os */ HEADR = 128L; if(INITTEXT == -1) INITTEXT = 0x10005000 + HEADR; @@ -144,7 +169,7 @@ if(INITRND == -1) INITRND = 4; break; - case 2: /* plan 9 */ + case Hplan9x32: /* plan 9 */ HEADR = 32L; if(INITTEXT == -1) INITTEXT = 4128; @@ -153,7 +178,7 @@ if(INITRND == -1) INITRND = 4096; break; - case 3: /* boot for NetBSD */ + case Hnetbsd: /* boot for NetBSD */ HEADR = 32L; if(INITTEXT == -1) INITTEXT = 0xF0000020L; @@ -162,7 +187,7 @@ if(INITRND == -1) INITRND = 4096; break; - case 4: /* boot for IXP1200 */ + case Hixp1200: /* boot for IXP1200 */ HEADR = 0L; if(INITTEXT == -1) INITTEXT = 0x0; @@ -171,7 +196,7 @@ if(INITRND == -1) INITRND = 4; break; - case 5: /* boot for ipaq */ + case Hipaq: /* boot for ipaq */ HEADR = 16L; if(INITTEXT == -1) INITTEXT = 0xC0008010; @@ -180,12 +205,23 @@ if(INITRND == -1) INITRND = 1024; break; + case Hlinux: /* arm elf */ + debug['d'] = 1; // no dynamic linking + elfinit(); + HEADR = ELFRESERVE; + if(INITTEXT == -1) + INITTEXT = 0x10000 + HEADR; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4096; + break; } if(INITDAT != 0 && INITRND != 0) - print("warning: -D0x%lux is ignored because of -R0x%lux\n", + print("warning: -D0x%ux is ignored because of -R0x%ux\n", INITDAT, INITRND); if(debug['v']) - Bprint(&bso, "HEADER = -H0x%d -T0x%lux -D0x%lux -R0x%lux\n", + Bprint(&bso, "HEADER = -H0x%d -T0x%ux -D0x%ux -R0x%ux\n", HEADTYPE, INITTEXT, INITDAT, INITRND); Bflush(&bso); zprg.as = AGOK; @@ -197,78 +233,52 @@ zprg.to = zprg.from; buildop(); histgen = 0; - textp = P; - datap = P; pc = 0; dtype = 4; - if(outfile == 0) - outfile = "5.out"; - cout = create(outfile, 1, 0775); - if(cout < 0) { - diag("%s: cannot create", outfile); - errorexit(); - } nuxiinit(); version = 0; cbp = buf.cbuf; cbc = sizeof(buf.cbuf); - firstp = prg(); - lastp = firstp; - if(INITENTRY == 0) { - INITENTRY = "_main"; - if(debug['p']) - INITENTRY = "_mainp"; - if(!debug['l']) - lookup(INITENTRY, 0)->type = SXREF; - } else - lookup(INITENTRY, 0)->type = SXREF; + addlibpath("command line", "command line", argv[0], "main"); + loadlib(); - while(*argv) - objfile(*argv++); - if(!debug['l']) - loadlib(); - firstp = firstp->link; - if(firstp == P) - goto out; - if(doexp || dlm){ - EXPTAB = "_exporttab"; - zerosig(EXPTAB); - zerosig("etext"); - zerosig("edata"); - zerosig("end"); - if(dlm){ - initdiv(); - import(); - HEADTYPE = 2; - INITTEXT = INITDAT = 0; - INITRND = 8; - INITENTRY = EXPTAB; - } - else - divsig(); - export(); + // mark some functions that are only referenced after linker code editing + // TODO(kaib): this doesn't work, the prog can't be found in runtime + for(i=0; ilink) - if(s->type == SXREF) - goto loop; -} - -void -errorexit(void) -{ - - if(nerrors) { - if(cout >= 0) - remove(outfile); - exits("error"); - } - exits(0); -} - -void -objfile(char *file) -{ - long off, esym, cnt, l; - int f, work; - Sym *s; - char magbuf[SARMAG]; - char name[100], pname[150]; - struct ar_hdr arhdr; - char *e, *start, *stop; - - if(file[0] == '-' && file[1] == 'l') { - if(debug['9']) - sprint(name, "/%s/lib/lib", thestring); - else - sprint(name, "/usr/%clib/lib", thechar); - strcat(name, file+2); - strcat(name, ".a"); - file = name; - } - if(debug['v']) - Bprint(&bso, "%5.2f ldobj: %s\n", cputime(), file); - Bflush(&bso); - f = open(file, 0); - if(f < 0) { - diag("cannot open file: %s", 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); -} - -int -zaddr(uchar *p, Adr *a, Sym *h[]) +static void +zaddr(Biobuf *f, Adr *a, Sym *h[]) { int i, c; - long l; + int32 l; Sym *s; Auto *u; - c = p[2]; + a->type = Bgetc(f); + a->reg = Bgetc(f); + c = Bgetc(f); if(c < 0 || c > NSYM){ print("sym out of range: %d\n", c); - p[0] = ALAST+1; - return 0; + Bputc(f, ALAST+1); + return; } - a->type = p[0]; - a->reg = p[1]; a->sym = h[c]; - a->name = p[3]; - c = 4; + a->name = Bgetc(f); - if(a->reg < 0 || a->reg > NREG) { + if((schar)a->reg < 0 || a->reg > NREG) { print("register out of range %d\n", a->reg); - p[0] = ALAST+1; - return 0; /* force real diagnostic */ + Bputc(f, ALAST+1); + return; /* force real diagnostic */ + } + + if(a->type == D_CONST || a->type == D_OCONST) { + if(a->name == D_EXTERN || a->name == D_STATIC) { + s = a->sym; + if(s != S && (s->type == STEXT || s->type == SCONST || s->type == SXREF)) { + if(0 && !s->fnptr && s->name[0] != '.') + print("%s used as function pointer\n", s->name); + s->fnptr = 1; // over the top cos of SXREF + } + } } switch(a->type) { default: print("unknown type %d\n", a->type); - p[0] = ALAST+1; - return 0; /* force real diagnostic */ + Bputc(f, ALAST+1); + return; /* force real diagnostic */ case D_NONE: case D_REG: @@ -458,51 +336,35 @@ break; case D_REGREG: - a->offset = p[4]; - c++; + a->offset = Bgetc(f); break; + case D_CONST2: + a->offset2 = Bget4(f); // fall through case D_BRANCH: case D_OREG: case D_CONST: case D_OCONST: case D_SHIFT: - a->offset = p[4] | (p[5]<<8) | - (p[6]<<16) | (p[7]<<24); - c += 4; + a->offset = Bget4(f); break; case D_SCONST: - while(nhunk < NSNAME) - gethunk(); - a->sval = (char*)hunk; - nhunk -= NSNAME; - hunk += NSNAME; - - memmove(a->sval, p+4, NSNAME); - c += NSNAME; + a->sval = mal(NSNAME); + Bread(f, a->sval, NSNAME); break; case D_FCONST: - while(nhunk < sizeof(Ieee)) - gethunk(); - a->ieee = (Ieee*)hunk; - nhunk -= NSNAME; - hunk += NSNAME; - - a->ieee->l = p[4] | (p[5]<<8) | - (p[6]<<16) | (p[7]<<24); - a->ieee->h = p[8] | (p[9]<<8) | - (p[10]<<16) | (p[11]<<24); - c += 8; + a->ieee.l = Bget4(f); + a->ieee.h = Bget4(f); break; } s = a->sym; if(s == S) - return c; + return; i = a->name; if(i != D_AUTO && i != D_PARAM) - return c; + return; l = a->offset; for(u=curauto; u; u=u->link) @@ -510,165 +372,15 @@ if(u->type == i) { if(u->aoffset > l) u->aoffset = l; - return c; + return; } - while(nhunk < sizeof(Auto)) - gethunk(); - u = (Auto*)hunk; - nhunk -= sizeof(Auto); - hunk += sizeof(Auto); - + u = mal(sizeof(Auto)); u->link = curauto; curauto = u; u->asym = s; u->aoffset = l; u->type = i; - return c; -} - -void -addlib(char *obj) -{ - char name[1024], comp[256], *p; - int i; - - if(histfrogp <= 0) - return; - - if(histfrog[0]->name[1] == '/') { - sprint(name, ""); - i = 1; - } else - if(histfrog[0]->name[1] == '.') { - sprint(name, "."); - i = 0; - } else { - if(debug['9']) - sprint(name, "/%s/lib", thestring); - else - sprint(name, "/usr/%clib", thechar); - i = 0; - } - - 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(name) + strlen(comp) + 3 >= sizeof(name)) { - diag("library component too long"); - return; - } - strcat(name, "/"); - strcat(name, comp); - } - 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) { - 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; } void @@ -679,47 +391,24 @@ p->to.type = D_NONE; } -uchar* -readsome(int f, uchar *buf, uchar *good, uchar *stop, int max) +void +ldobj1(Biobuf *f, char *pkg, int64 len, char *pn) { - int n; + int32 ipc; + Prog *p; + Sym *h[NSYM], *s; + int v, o, r, skip; + uint32 sig; + char *name; + int ntext; + int32 eof; + char src[1024], *x; + Prog *lastp; - 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; -} - -void -ldobj(int f, long c, char *pn) -{ - long ipc; - Prog *p, *t; - uchar *bloc, *bsize, *stop; - Sym *h[NSYM], *s, *di; - int v, o, r, skip; - ulong sig; - static int files; - static char **filen; - char **nfilen; - - if((files&15) == 0){ - nfilen = malloc((files+16)*sizeof(char*)); - memmove(nfilen, filen, files*sizeof(char*)); - free(filen); - filen = nfilen; - } - filen[files++] = strdup(pn); - - bsize = buf.xbuf; - bloc = buf.xbuf; - di = S; + lastp = nil; + ntext = 0; + eof = Boffset(f) + len; + src[0] = 0; newloop: memset(h, 0, sizeof(h)); @@ -729,62 +418,52 @@ skip = 0; loop: - if(c <= 0) + if(f->state == Bracteof || Boffset(f) >= eof) goto eof; - r = bsize - bloc; - if(r < 100 && r < c) { /* enough for largest prog */ - bsize = readsome(f, buf.xbuf, bloc, bsize, c); - if(bsize == 0) - goto eof; - bloc = buf.xbuf; - goto loop; - } - o = bloc[0]; /* as */ + o = Bgetc(f); + if(o == Beof) + goto eof; + if(o <= AXXX || o >= ALAST) { - diag("%s: line %ld: opcode out of range %d", pn, pc-ipc, o); + diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o); print(" probably not a .5 file\n"); errorexit(); } if(o == ANAME || o == ASIGNAME) { sig = 0; - if(o == ASIGNAME){ - sig = bloc[1] | (bloc[2]<<8) | (bloc[3]<<16) | (bloc[4]<<24); - bloc += 4; - c -= 4; - } - stop = memchr(&bloc[3], 0, bsize-&bloc[3]); - if(stop == 0){ - bsize = readsome(f, buf.xbuf, bloc, bsize, c); - if(bsize == 0) - goto eof; - bloc = buf.xbuf; - stop = memchr(&bloc[3], 0, bsize-&bloc[3]); - if(stop == 0){ + if(o == ASIGNAME) + sig = Bget4(f); + v = Bgetc(f); /* type */ + o = Bgetc(f); /* sym */ + r = 0; + if(v == D_STATIC) + r = version; + name = Brdline(f, '\0'); + if(name == nil) { + if(Blinelen(f) > 0) { fprint(2, "%s: name too long\n", pn); errorexit(); } + goto eof; } - v = bloc[1]; /* type */ - o = bloc[2]; /* sym */ - bloc += 3; - c -= 3; - - r = 0; - if(v == D_STATIC) - r = version; - s = lookup((char*)bloc, r); - c -= &stop[1] - bloc; - bloc = stop + 1; + x = expandpkg(name, pkg); + s = lookup(x, r); + if(x != name) + free(x); if(sig != 0){ if(s->sig != 0 && s->sig != sig) - diag("incompatible type signatures %lux(%s) and %lux(%s) for %s", s->sig, filen[s->file], sig, pn, s->name); + diag("incompatible type signatures %ux(%s) and %ux(%s) for %s", s->sig, s->file, sig, pn, s->name); s->sig = sig; - s->file = files-1; + s->file = pn; } if(debug['W']) print(" ANAME %s\n", s->name); + if(o < 0 || o >= nelem(h)) { + fprint(2, "%s: mangled input file\n", pn); + errorexit(); + } h[o] = s; if((v == D_EXTERN || v == D_STATIC) && s->type == 0) s->type = SXREF; @@ -803,24 +482,17 @@ goto loop; } - if(nhunk < sizeof(Prog)) - gethunk(); - p = (Prog*)hunk; - nhunk -= sizeof(Prog); - hunk += sizeof(Prog); + p = mal(sizeof(Prog)); + p->as = o; + p->scond = Bgetc(f); + p->reg = Bgetc(f); + p->line = Bget4(f); - p->as = o; - p->scond = bloc[1]; - p->reg = bloc[2]; - p->line = bloc[3] | (bloc[4]<<8) | (bloc[5]<<16) | (bloc[6]<<24); + zaddr(f, &p->from, h); + zaddr(f, &p->to, h); - r = zaddr(bloc+7, &p->from, h) + 7; - r += zaddr(bloc+r, &p->to, h); - bloc += r; - c -= r; - - if(p->reg > NREG) - diag("register out of range %d", p->reg); + if(p->as != ATEXT && p->as != AGLOBL && p->reg > NREG) + diag("register out of range %A %d", p->as, p->reg); p->link = P; p->cond = P; @@ -831,10 +503,12 @@ switch(o) { case AHISTORY: if(p->to.offset == -1) { - addlib(pn); + addlib(src, pn); histfrogp = 0; goto loop; } + if(src[0] == '\0') + copyhistfrog(src, sizeof src); addhist(p->line, D_FILE); /* 'z' */ if(p->to.offset) addhist(p->to.offset, D_FILE1); /* 'Z' */ @@ -843,13 +517,13 @@ case AEND: histtoauto(); - if(curtext != P) - curtext->to.autom = curauto; + if(cursym != nil && cursym->text) + cursym->autom = curauto; curauto = 0; - curtext = P; - if(c) - goto newloop; - return; + cursym = nil; + if(Boffset(f) == eof) + return; + goto newloop; case AGLOBL: s = p->from.sym; @@ -866,61 +540,31 @@ s->type = SBSS; s->value = 0; } - if(p->to.offset > s->value) - s->value = p->to.offset; + if(p->to.offset > s->size) + s->size = p->to.offset; + if(p->reg & DUPOK) + s->dupok = 1; break; - case ADYNT: - if(p->to.sym == S) { - diag("DYNT without a sym\n%P", p); - break; + case ADATA: + // Assume that AGLOBL comes after ADATA. + // If we've seen an AGLOBL that said this sym was DUPOK, + // ignore any more ADATA we see, which must be + // redefinitions. + s = p->from.sym; + if(s->dupok) { + if(debug['v']) + Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn); + goto loop; } - di = p->to.sym; - p->reg = 4; - if(di->type == SXREF) { - if(debug['z']) - Bprint(&bso, "%P set to %d\n", p, dtype); - di->type = SCONST; - di->value = dtype; - dtype += 4; + if(s->file == nil) + s->file = pn; + else if(s->file != pn) { + diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn); + errorexit(); } - if(p->from.sym == S) - break; - - p->from.offset = di->value; - p->from.sym->type = SDATA; - if(curtext == P) { - diag("DYNT not in text: %P", p); - break; - } - p->to.sym = curtext->from.sym; - p->to.type = D_CONST; - p->link = datap; - datap = p; - break; - - case AINIT: - if(p->from.sym == S) { - diag("INIT without a sym\n%P", p); - break; - } - if(di == S) { - diag("INIT without previous DYNT\n%P", p); - break; - } - p->from.offset = di->value; - p->from.sym->type = SDATA; - p->link = datap; - datap = p; - break; - - case ADATA: - if(p->from.sym == S) { - diag("DATA without a sym\n%P", p); - break; - } - p->link = datap; - datap = p; + savedata(s, p, pn); + unmal(p, sizeof *p); break; case AGOK: @@ -930,21 +574,24 @@ break; case ATEXT: - if(curtext != P) { + if(cursym != nil && cursym->text) { histtoauto(); - curtext->to.autom = curauto; + cursym->autom = curauto; curauto = 0; } - skip = 0; - curtext = p; - autosize = (p->to.offset+3L) & ~3L; - p->to.offset = autosize; - autosize += 4; s = p->from.sym; if(s == S) { diag("TEXT must have a name\n%P", p); errorexit(); } + cursym = s; + if(ntext++ == 0 && s->type != 0 && s->type != SXREF) { + /* redefinition, so file has probably been seen before */ + if(debug['v']) + Bprint(&bso, "skipping: %s: redefinition: %s", pn, s->name); + return; + } + skip = 0; if(s->type != 0 && s->type != SXREF) { if(p->reg & DUPOK) { skip = 1; @@ -952,19 +599,21 @@ } diag("redefinition: %s\n%P", s->name, p); } + if(etextp) + etextp->next = s; + else + textp = s; + etextp = s; + p->align = 4; + autosize = (p->to.offset+3L) & ~3L; + p->to.offset = autosize; + autosize += 4; s->type = STEXT; + s->text = p; s->value = pc; - lastp->link = p; lastp = p; p->pc = pc; pc++; - if(textp == P) { - textp = p; - etextp = p; - goto loop; - } - etextp->cond = p; - etextp = p; break; case ASUB: @@ -985,27 +634,39 @@ } goto casedef; + case AMOVWD: + case AMOVWF: + case AMOVDW: + case AMOVFW: + case AMOVFD: + case AMOVDF: + // case AMOVF: + // case AMOVD: + case ACMPF: + case ACMPD: + case AADDF: + case AADDD: + case ASUBF: + case ASUBD: + case AMULF: + case AMULD: + case ADIVF: + case ADIVD: + goto casedef; + case AMOVF: if(skip) goto casedef; - if(p->from.type == D_FCONST && chipfloat(p->from.ieee) < 0) { + if(p->from.type == D_FCONST && chipfloat(&p->from.ieee) < 0 && + (chipzero(&p->from.ieee) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) { /* size sb 9 max */ - sprint(literal, "$%lux", ieeedtof(p->from.ieee)); + sprint(literal, "$%ux", ieeedtof(&p->from.ieee)); s = lookup(literal, 0); if(s->type == 0) { s->type = SBSS; - s->value = 4; - t = prg(); - t->as = ADATA; - t->line = p->line; - t->from.type = D_OREG; - t->from.sym = s; - t->from.name = D_EXTERN; - t->reg = 4; - t->to = p->from; - t->link = datap; - datap = t; + adduint32(s, ieeedtof(&p->from.ieee)); + s->reachable = 0; } p->from.type = D_OREG; p->from.sym = s; @@ -1018,24 +679,17 @@ if(skip) goto casedef; - if(p->from.type == D_FCONST && chipfloat(p->from.ieee) < 0) { + if(p->from.type == D_FCONST && chipfloat(&p->from.ieee) < 0 && + (chipzero(&p->from.ieee) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) { /* size sb 18 max */ - sprint(literal, "$%lux.%lux", - p->from.ieee->l, p->from.ieee->h); + sprint(literal, "$%ux.%ux", + p->from.ieee.l, p->from.ieee.h); s = lookup(literal, 0); if(s->type == 0) { s->type = SBSS; - s->value = 8; - t = prg(); - t->as = ADATA; - t->line = p->line; - t->from.type = D_OREG; - t->from.sym = s; - t->from.name = D_EXTERN; - t->reg = 8; - t->to = p->from; - t->link = datap; - datap = t; + adduint32(s, p->from.ieee.l); + adduint32(s, p->from.ieee.h); + s->reachable = 0; } p->from.type = D_OREG; p->from.sym = s; @@ -1048,13 +702,17 @@ casedef: if(skip) nopout(p); - + p->pc = pc; + pc++; if(p->to.type == D_BRANCH) p->to.offset += ipc; + if(lastp == nil) { + if(p->as != ANOP) + diag("unexpected instruction: %P", p); + break; + } lastp->link = p; lastp = p; - p->pc = pc; - pc++; break; } goto loop; @@ -1063,458 +721,24 @@ diag("truncated object file: %s", pn); } -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; - - while(nhunk < sizeof(Sym)) - gethunk(); - s = (Sym*)hunk; - nhunk -= sizeof(Sym); - hunk += sizeof(Sym); - - s->name = malloc(l); - 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; -} - Prog* prg(void) { Prog *p; - while(nhunk < sizeof(Prog)) - gethunk(); - p = (Prog*)hunk; - nhunk -= sizeof(Prog); - hunk += sizeof(Prog); - + p = mal(sizeof(Prog)); *p = zprg; return p; } -void -gethunk(void) +Prog* +appendp(Prog *q) { - char *h; - long nh; + Prog *p; - nh = NHUNK; - if(thunk >= 5L*NHUNK) { - nh = 5L*NHUNK; - if(thunk >= 25L*NHUNK) - nh = 25L*NHUNK; - } - h = mysbrk(nh); - if(h == (char*)-1) { - diag("out of memory"); - errorexit(); - } - hunk = h; - nhunk = nh; - thunk += nh; + p = prg(); + p->link = q->link; + q->link = p; + p->line = q->line; + return p; } - -void -doprof1(void) -{ - Sym *s; - long n; - Prog *p, *q; - - if(debug['v']) - Bprint(&bso, "%5.2f profile 1\n", cputime()); - Bflush(&bso); - s = lookup("__mcount", 0); - n = 1; - for(p = firstp->link; p != P; p = p->link) { - if(p->as == ATEXT) { - q = prg(); - q->line = p->line; - q->link = datap; - datap = q; - q->as = ADATA; - q->from.type = D_OREG; - q->from.name = D_EXTERN; - q->from.offset = n*4; - q->from.sym = s; - q->reg = 4; - q->to = p->from; - q->to.type = D_CONST; - - q = prg(); - q->line = p->line; - q->pc = p->pc; - q->link = p->link; - p->link = q; - p = q; - p->as = AMOVW; - p->from.type = D_OREG; - p->from.name = D_EXTERN; - p->from.sym = s; - p->from.offset = n*4 + 4; - p->to.type = D_REG; - p->to.reg = REGTMP; - - q = prg(); - q->line = p->line; - q->pc = p->pc; - q->link = p->link; - p->link = q; - p = q; - p->as = AADD; - p->from.type = D_CONST; - p->from.offset = 1; - p->to.type = D_REG; - p->to.reg = REGTMP; - - q = prg(); - q->line = p->line; - q->pc = p->pc; - q->link = p->link; - p->link = q; - p = q; - p->as = AMOVW; - p->from.type = D_REG; - p->from.reg = REGTMP; - p->to.type = D_OREG; - p->to.name = D_EXTERN; - p->to.sym = s; - p->to.offset = n*4 + 4; - - n += 2; - continue; - } - } - q = prg(); - q->line = 0; - q->link = datap; - datap = q; - - q->as = ADATA; - q->from.type = D_OREG; - q->from.name = D_EXTERN; - q->from.sym = s; - q->reg = 4; - q->to.type = D_CONST; - q->to.offset = n; - - s->type = SBSS; - s->value = n*4; -} - -void -doprof2(void) -{ - Sym *s2, *s4; - Prog *p, *q, *q2, *ps2, *ps4; - - if(debug['v']) - Bprint(&bso, "%5.2f profile 2\n", cputime()); - Bflush(&bso); - - if(debug['e']){ - s2 = lookup("_tracein", 0); - s4 = lookup("_traceout", 0); - }else{ - s2 = lookup("_profin", 0); - s4 = lookup("_profout", 0); - } - if(s2->type != STEXT || s4->type != STEXT) { - if(debug['e']) - diag("_tracein/_traceout not defined %d %d", s2->type, s4->type); - else - diag("_profin/_profout not defined"); - return; - } - - ps2 = P; - ps4 = P; - for(p = firstp; p != P; p = p->link) { - if(p->as == ATEXT) { - if(p->from.sym == s2) { - ps2 = p; - p->reg = 1; - } - if(p->from.sym == s4) { - ps4 = p; - p->reg = 1; - } - } - } - for(p = firstp; p != P; p = p->link) { - if(p->as == ATEXT) { - if(p->reg & NOPROF) { - for(;;) { - q = p->link; - if(q == P) - break; - if(q->as == ATEXT) - break; - p = q; - } - continue; - } - - /* - * BL profin, R2 - */ - q = prg(); - q->line = p->line; - q->pc = p->pc; - q->link = p->link; - if(debug['e']){ /* embedded tracing */ - q2 = prg(); - p->link = q2; - q2->link = q; - - q2->line = p->line; - q2->pc = p->pc; - - q2->as = AB; - q2->to.type = D_BRANCH; - q2->to.sym = p->to.sym; - q2->cond = q->link; - }else - p->link = q; - p = q; - p->as = ABL; - p->to.type = D_BRANCH; - p->cond = ps2; - p->to.sym = s2; - - continue; - } - if(p->as == ARET) { - /* - * RET (default) - */ - if(debug['e']){ /* embedded tracing */ - q = prg(); - q->line = p->line; - q->pc = p->pc; - q->link = p->link; - p->link = q; - p = q; - } - /* - * RET - */ - q = prg(); - q->as = ARET; - q->from = p->from; - q->to = p->to; - q->link = p->link; - p->link = q; - - /* - * BL profout - */ - p->as = ABL; - p->from = zprg.from; - p->to = zprg.to; - p->to.type = D_BRANCH; - p->cond = ps4; - p->to.sym = s4; - - p = q; - - continue; - } - } -} - -void -nuxiinit(void) -{ - - int i, c; - - for(i=0; i<4; i++) { - c = find1(0x04030201L, i+1); - if(i < 2) - inuxi2[i] = c; - if(i < 1) - inuxi1[i] = c; - inuxi4[i] = c; - fnuxi4[i] = c; - if(debug['d'] == 0){ - fnuxi8[i] = c; - fnuxi8[i+4] = c+4; - } - else{ - fnuxi8[i] = c+4; /* ms word first, then ls, even in little endian mode */ - fnuxi8[i+4] = c; - } - } - if(debug['v']) { - Bprint(&bso, "inuxi = "); - for(i=0; i<1; i++) - Bprint(&bso, "%d", inuxi1[i]); - Bprint(&bso, " "); - for(i=0; i<2; i++) - Bprint(&bso, "%d", inuxi2[i]); - Bprint(&bso, " "); - for(i=0; i<4; i++) - Bprint(&bso, "%d", inuxi4[i]); - Bprint(&bso, "\nfnuxi = "); - for(i=0; i<4; i++) - Bprint(&bso, "%d", fnuxi4[i]); - Bprint(&bso, " "); - for(i=0; i<8; i++) - Bprint(&bso, "%d", fnuxi8[i]); - Bprint(&bso, "\n"); - } - Bflush(&bso); -} - -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); -} - -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 -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); -} diff -r d8d00747375b sys/src/cmd/5l/optab.c --- a/sys/src/cmd/5l/optab.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/5l/optab.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,9 +1,39 @@ +// Inferno utils/5l/optab.c +// http://code.google.com/p/inferno-os/source/browse/utils/5l/optab.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" Optab optab[] = { - { ATEXT, C_LEXT, C_NONE, C_LCON, 0, 0, 0 }, - { ATEXT, C_LEXT, C_REG, C_LCON, 0, 0, 0 }, + /* struct Optab: + OPCODE, from, prog->reg, to, type,size,param,flag */ { ATEXT, C_ADDR, C_NONE, C_LCON, 0, 0, 0 }, { ATEXT, C_ADDR, C_REG, C_LCON, 0, 0, 0 }, @@ -24,15 +54,17 @@ { AMVN, C_SHIFT,C_NONE, C_REG, 3, 4, 0 }, { ACMP, C_SHIFT,C_REG, C_NONE, 3, 4, 0 }, - { AMOVW, C_RECON,C_NONE, C_REG, 4, 4, REGSB }, { AMOVW, C_RACON,C_NONE, C_REG, 4, 4, REGSP }, { AB, C_NONE, C_NONE, C_SBRA, 5, 4, 0, LPOOL }, { ABL, C_NONE, C_NONE, C_SBRA, 5, 4, 0 }, + { ABX, C_NONE, C_NONE, C_SBRA, 74, 20, 0 }, { ABEQ, C_NONE, C_NONE, C_SBRA, 5, 4, 0 }, { AB, C_NONE, C_NONE, C_ROREG, 6, 4, 0, LPOOL }, { ABL, C_NONE, C_NONE, C_ROREG, 7, 8, 0 }, + { ABX, C_NONE, C_NONE, C_ROREG, 75, 12, 0 }, + { ABXRET, C_NONE, C_NONE, C_ROREG, 76, 4, 0 }, { ASLL, C_RCON, C_REG, C_REG, 8, 4, 0 }, { ASLL, C_RCON, C_NONE, C_REG, 8, 4, 0 }, @@ -42,9 +74,9 @@ { ASWI, C_NONE, C_NONE, C_NONE, 10, 4, 0 }, { ASWI, C_NONE, C_NONE, C_LOREG, 10, 4, 0 }, + { ASWI, C_NONE, C_NONE, C_LCON, 10, 4, 0 }, { AWORD, C_NONE, C_NONE, C_LCON, 11, 4, 0 }, - { AWORD, C_NONE, C_NONE, C_LEXT, 11, 4, 0 }, { AWORD, C_NONE, C_NONE, C_ADDR, 11, 4, 0 }, { AMOVW, C_NCON, C_NONE, C_REG, 12, 4, 0 }, @@ -72,85 +104,35 @@ { AMULL, C_REG, C_REG, C_REGREG, 17, 4, 0 }, - { AMOVW, C_REG, C_NONE, C_SEXT, 20, 4, REGSB }, { AMOVW, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP }, { AMOVW, C_REG, C_NONE, C_SOREG, 20, 4, 0 }, - { AMOVB, C_REG, C_NONE, C_SEXT, 20, 4, REGSB }, { AMOVB, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP }, { AMOVB, C_REG, C_NONE, C_SOREG, 20, 4, 0 }, - { AMOVBU, C_REG, C_NONE, C_SEXT, 20, 4, REGSB }, { AMOVBU, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP }, { AMOVBU, C_REG, C_NONE, C_SOREG, 20, 4, 0 }, - { AMOVW, C_SEXT, C_NONE, C_REG, 21, 4, REGSB }, { AMOVW, C_SAUTO,C_NONE, C_REG, 21, 4, REGSP }, { AMOVW, C_SOREG,C_NONE, C_REG, 21, 4, 0 }, - { AMOVBU, C_SEXT, C_NONE, C_REG, 21, 4, REGSB }, { AMOVBU, C_SAUTO,C_NONE, C_REG, 21, 4, REGSP }, { AMOVBU, C_SOREG,C_NONE, C_REG, 21, 4, 0 }, - { AMOVB, C_SEXT, C_NONE, C_REG, 22, 12, REGSB }, - { AMOVB, C_SAUTO,C_NONE, C_REG, 22, 12, REGSP }, - { AMOVB, C_SOREG,C_NONE, C_REG, 22, 12, 0 }, - { AMOVH, C_SEXT, C_NONE, C_REG, 22, 12, REGSB }, - { AMOVH, C_SAUTO,C_NONE, C_REG, 22, 12, REGSP }, - { AMOVH, C_SOREG,C_NONE, C_REG, 22, 12, 0 }, - { AMOVHU, C_SEXT, C_NONE, C_REG, 22, 12, REGSB }, - { AMOVHU, C_SAUTO,C_NONE, C_REG, 22, 12, REGSP }, - { AMOVHU, C_SOREG,C_NONE, C_REG, 22, 12, 0 }, - - { AMOVH, C_REG, C_NONE, C_SEXT, 23, 12, REGSB }, - { AMOVH, C_REG, C_NONE, C_SAUTO, 23, 12, REGSP }, - { AMOVH, C_REG, C_NONE, C_SOREG, 23, 12, 0 }, - { AMOVHU, C_REG, C_NONE, C_SEXT, 23, 12, REGSB }, - { AMOVHU, C_REG, C_NONE, C_SAUTO, 23, 12, REGSP }, - { AMOVHU, C_REG, C_NONE, C_SOREG, 23, 12, 0 }, - - { AMOVW, C_REG, C_NONE, C_LEXT, 30, 8, REGSB, LTO }, { AMOVW, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO }, { AMOVW, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO }, { AMOVW, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO }, - { AMOVB, C_REG, C_NONE, C_LEXT, 30, 8, REGSB, LTO }, { AMOVB, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO }, { AMOVB, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO }, { AMOVB, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO }, - { AMOVBU, C_REG, C_NONE, C_LEXT, 30, 8, REGSB, LTO }, { AMOVBU, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO }, { AMOVBU, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO }, { AMOVBU, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO }, - { AMOVW, C_LEXT, C_NONE, C_REG, 31, 8, REGSB, LFROM }, { AMOVW, C_LAUTO,C_NONE, C_REG, 31, 8, REGSP, LFROM }, { AMOVW, C_LOREG,C_NONE, C_REG, 31, 8, 0, LFROM }, { AMOVW, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM }, - { AMOVBU, C_LEXT, C_NONE, C_REG, 31, 8, REGSB, LFROM }, { AMOVBU, C_LAUTO,C_NONE, C_REG, 31, 8, REGSP, LFROM }, { AMOVBU, C_LOREG,C_NONE, C_REG, 31, 8, 0, LFROM }, { AMOVBU, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM }, - { AMOVB, C_LEXT, C_NONE, C_REG, 32, 16, REGSB, LFROM }, - { AMOVB, C_LAUTO,C_NONE, C_REG, 32, 16, REGSP, LFROM }, - { AMOVB, C_LOREG,C_NONE, C_REG, 32, 16, 0, LFROM }, - { AMOVB, C_ADDR, C_NONE, C_REG, 66, 16, 0, LFROM }, - { AMOVH, C_LEXT, C_NONE, C_REG, 32, 16, REGSB, LFROM }, - { AMOVH, C_LAUTO,C_NONE, C_REG, 32, 16, REGSP, LFROM }, - { AMOVH, C_LOREG,C_NONE, C_REG, 32, 16, 0, LFROM }, - { AMOVH, C_ADDR, C_NONE, C_REG, 66, 16, 0, LFROM }, - { AMOVHU, C_LEXT, C_NONE, C_REG, 32, 16, REGSB, LFROM }, - { AMOVHU, C_LAUTO,C_NONE, C_REG, 32, 16, REGSP, LFROM }, - { AMOVHU, C_LOREG,C_NONE, C_REG, 32, 16, 0, LFROM }, - { AMOVHU, C_ADDR, C_NONE, C_REG, 66, 16, 0, LFROM }, - - { AMOVH, C_REG, C_NONE, C_LEXT, 33, 24, REGSB, LTO }, - { AMOVH, C_REG, C_NONE, C_LAUTO, 33, 24, REGSP, LTO }, - { AMOVH, C_REG, C_NONE, C_LOREG, 33, 24, 0, LTO }, - { AMOVH, C_REG, C_NONE, C_ADDR, 67, 24, 0, LTO }, - { AMOVHU, C_REG, C_NONE, C_LEXT, 33, 24, REGSB, LTO }, - { AMOVHU, C_REG, C_NONE, C_LAUTO, 33, 24, REGSP, LTO }, - { AMOVHU, C_REG, C_NONE, C_LOREG, 33, 24, 0, LTO }, - { AMOVHU, C_REG, C_NONE, C_ADDR, 67, 24, 0, LTO }, - - { AMOVW, C_LECON,C_NONE, C_REG, 34, 8, REGSB, LFROM }, { AMOVW, C_LACON,C_NONE, C_REG, 34, 8, REGSP, LFROM }, { AMOVW, C_PSR, C_NONE, C_REG, 35, 4, 0 }, @@ -164,19 +146,15 @@ { ARFE, C_NONE, C_NONE, C_NONE, 41, 4, 0 }, - { AMOVF, C_FREG, C_NONE, C_FEXT, 50, 4, REGSB }, { AMOVF, C_FREG, C_NONE, C_FAUTO, 50, 4, REGSP }, { AMOVF, C_FREG, C_NONE, C_FOREG, 50, 4, 0 }, - { AMOVF, C_FEXT, C_NONE, C_FREG, 51, 4, REGSB }, { AMOVF, C_FAUTO,C_NONE, C_FREG, 51, 4, REGSP }, { AMOVF, C_FOREG,C_NONE, C_FREG, 51, 4, 0 }, - { AMOVF, C_FREG, C_NONE, C_LEXT, 52, 12, REGSB, LTO }, { AMOVF, C_FREG, C_NONE, C_LAUTO, 52, 12, REGSP, LTO }, { AMOVF, C_FREG, C_NONE, C_LOREG, 52, 12, 0, LTO }, - { AMOVF, C_LEXT, C_NONE, C_FREG, 53, 12, REGSB, LFROM }, { AMOVF, C_LAUTO,C_NONE, C_FREG, 53, 12, REGSP, LFROM }, { AMOVF, C_LOREG,C_NONE, C_FREG, 53, 12, 0, LFROM }, @@ -185,17 +163,8 @@ { AADDF, C_FREG, C_NONE, C_FREG, 54, 4, 0 }, { AADDF, C_FREG, C_REG, C_FREG, 54, 4, 0 }, - { AADDF, C_FCON, C_NONE, C_FREG, 54, 4, 0 }, - { AADDF, C_FCON, C_REG, C_FREG, 54, 4, 0 }, - { AMOVF, C_FCON, C_NONE, C_FREG, 54, 4, 0 }, { AMOVF, C_FREG, C_NONE, C_FREG, 54, 4, 0 }, - { ACMPF, C_FREG, C_REG, C_NONE, 54, 4, 0 }, - { ACMPF, C_FCON, C_REG, C_NONE, 54, 4, 0 }, - - { AMOVFW, C_FREG, C_NONE, C_REG, 55, 4, 0 }, - { AMOVFW, C_REG, C_NONE, C_FREG, 55, 4, 0 }, - { AMOVW, C_REG, C_NONE, C_FCR, 56, 4, 0 }, { AMOVW, C_FCR, C_NONE, C_REG, 57, 4, 0 }, @@ -211,39 +180,57 @@ { ACASE, C_REG, C_NONE, C_NONE, 62, 4, 0 }, { ABCASE, C_NONE, C_NONE, C_SBRA, 63, 4, 0 }, - { AMOVH, C_REG, C_NONE, C_HEXT, 70, 4, REGSB, V4 }, - { AMOVH, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, V4 }, - { AMOVH, C_REG, C_NONE, C_HOREG, 70, 4, 0, V4 }, - { AMOVHU, C_REG, C_NONE, C_HEXT, 70, 4, REGSB, V4 }, - { AMOVHU, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, V4 }, - { AMOVHU, C_REG, C_NONE, C_HOREG, 70, 4, 0, V4 }, + { AMOVH, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 }, + { AMOVH, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 }, + { AMOVHU, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 }, + { AMOVHU, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 }, - { AMOVB, C_HEXT, C_NONE, C_REG, 71, 4, REGSB, V4 }, - { AMOVB, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, V4 }, - { AMOVB, C_HOREG,C_NONE, C_REG, 71, 4, 0, V4 }, - { AMOVH, C_HEXT, C_NONE, C_REG, 71, 4, REGSB, V4 }, - { AMOVH, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, V4 }, - { AMOVH, C_HOREG,C_NONE, C_REG, 71, 4, 0, V4 }, - { AMOVHU, C_HEXT, C_NONE, C_REG, 71, 4, REGSB, V4 }, - { AMOVHU, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, V4 }, - { AMOVHU, C_HOREG,C_NONE, C_REG, 71, 4, 0, V4 }, + { AMOVB, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 }, + { AMOVB, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 }, + { AMOVH, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 }, + { AMOVH, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 }, + { AMOVHU, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 }, + { AMOVHU, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 }, - { AMOVH, C_REG, C_NONE, C_LEXT, 72, 8, REGSB, LTO|V4 }, - { AMOVH, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO|V4 }, - { AMOVH, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO|V4 }, - { AMOVHU, C_REG, C_NONE, C_LEXT, 72, 8, REGSB, LTO|V4 }, - { AMOVHU, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO|V4 }, - { AMOVHU, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO|V4 }, + { AMOVH, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO }, + { AMOVH, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO }, + { AMOVH, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO }, + { AMOVHU, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO }, + { AMOVHU, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO }, + { AMOVHU, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO }, - { AMOVB, C_LEXT, C_NONE, C_REG, 73, 8, REGSB, LFROM|V4 }, - { AMOVB, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM|V4 }, - { AMOVB, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM|V4 }, - { AMOVH, C_LEXT, C_NONE, C_REG, 73, 8, REGSB, LFROM|V4 }, - { AMOVH, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM|V4 }, - { AMOVH, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM|V4 }, - { AMOVHU, C_LEXT, C_NONE, C_REG, 73, 8, REGSB, LFROM|V4 }, - { AMOVHU, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM|V4 }, - { AMOVHU, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM|V4 }, + { AMOVB, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM }, + { AMOVB, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM }, + { AMOVB, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM }, + { AMOVH, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM }, + { AMOVH, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM }, + { AMOVH, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM }, + { AMOVHU, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM }, + { AMOVHU, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM }, + { AMOVHU, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM }, + + { ALDREX, C_SOREG,C_NONE, C_REG, 77, 4, 0 }, + { ASTREX, C_SOREG,C_REG, C_REG, 78, 4, 0 }, + + { AMOVF, C_ZFCON,C_NONE, C_FREG, 80, 8, 0 }, + { AMOVF, C_SFCON,C_NONE, C_FREG, 81, 4, 0 }, + + { ACMPF, C_FREG, C_REG, C_NONE, 82, 8, 0 }, + { ACMPF, C_FREG, C_NONE, C_NONE, 83, 8, 0 }, + + { AMOVFW, C_FREG, C_NONE, C_FREG, 84, 4, 0 }, + { AMOVWF, C_FREG, C_NONE, C_FREG, 85, 4, 0 }, + + { AMOVFW, C_FREG, C_NONE, C_REG, 86, 8, 0 }, + { AMOVWF, C_REG, C_NONE, C_FREG, 87, 8, 0 }, + + { AMOVW, C_REG, C_NONE, C_FREG, 88, 4, 0 }, + { AMOVW, C_FREG, C_NONE, C_REG, 89, 4, 0 }, + + { ATST, C_REG, C_NONE, C_NONE, 90, 4, 0 }, + + { ALDREXD, C_SOREG,C_NONE, C_REG, 91, 4, 0 }, + { ASTREXD, C_SOREG,C_REG, C_REG, 92, 4, 0 }, { AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0 }, }; diff -r d8d00747375b sys/src/cmd/5l/pass.c --- a/sys/src/cmd/5l/pass.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/5l/pass.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,124 +1,39 @@ +// Inferno utils/5l/pass.c +// http://code.google.com/p/inferno-os/source/browse/utils/5l/pass.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. + +// Code and data passes. + #include "l.h" +#include "../ld/lib.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 (%ld): %s\n%P", - 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 - * (rational is that data segment is more easily - * addressed through offset on R12) - */ - 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; - } - while(v & 3) - v++; - s->value = v; - if(v > MINSIZ) - continue; - 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; - 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; - s->value = orig; - orig += v; - } - while(orig & 7) - orig++; - bsssize = orig-datsize; - - xdefine("setR12", SDATA, 0L+BIG); - xdefine("bdata", SDATA, 0L); - xdefine("edata", SDATA, datsize); - xdefine("end", SBSS, datsize+bsssize); - xdefine("etext", STEXT, 0L); -} - -void -undef(void) -{ - int i; - Sym *s; - - for(i=0; ilink) - if(s->type == SXREF) - diag("%s: not defined", s->name); -} +static void xfol(Prog*, Prog**); Prog* brchain(Prog *p) @@ -161,20 +76,23 @@ void follow(void) { + Prog *firstp, *lastp; + if(debug['v']) Bprint(&bso, "%5.2f follow\n", cputime()); Bflush(&bso); - firstp = prg(); - lastp = firstp; - xfol(textp); - - firstp = firstp->link; - lastp->link = P; + for(cursym = textp; cursym != nil; cursym = cursym->next) { + firstp = prg(); + lastp = firstp; + xfol(cursym->text, &lastp); + lastp->link = nil; + cursym->text = firstp->link; + } } -void -xfol(Prog *p) +static void +xfol(Prog *p, Prog **last) { Prog *q, *r; int a, i; @@ -183,11 +101,9 @@ if(p == P) return; a = p->as; - if(a == ATEXT) - curtext = p; if(a == AB) { q = p->cond; - if(q != P) { + if(q != P && q->as != ATEXT) { p->mark |= FOLL; p = q; if(!(p->mark & FOLL)) @@ -196,7 +112,7 @@ } if(p->mark & FOLL) { for(i=0,q=p; i<4; i++,q=q->link) { - if(q == lastp) + if(q == *last || q == nil) break; a = q->as; if(a == ANOP) { @@ -205,7 +121,7 @@ } if(a == AB || (a == ARET && q->scond == 14) || a == ARFE) goto copy; - if(!q->cond || (q->cond->mark&FOLL)) + if(q->cond == P || (q->cond->mark&FOLL)) continue; if(a != ABEQ && a != ABNE) continue; @@ -218,12 +134,12 @@ r->mark |= FOLL; if(p != q) { p = p->link; - lastp->link = r; - lastp = r; + (*last)->link = r; + *last = r; continue; } - lastp->link = r; - lastp = r; + (*last)->link = r; + *last = r; if(a == AB || (a == ARET && q->scond == 14) || a == ARFE) return; r->as = ABNE; @@ -232,7 +148,7 @@ r->cond = p->link; r->link = p->cond; if(!(r->link->mark&FOLL)) - xfol(r->link); + xfol(r->link, last); if(!(r->cond->mark&FOLL)) print("cant happen 2\n"); return; @@ -248,13 +164,13 @@ p = q; } p->mark |= FOLL; - lastp->link = p; - lastp = p; + (*last)->link = p; + *last = p; if(a == AB || (a == ARET && p->scond == 14) || a == ARFE){ return; } if(p->cond != P) - if(a != ABL && p->link != P) { + if(a != ABL && a != ABX && p->link != P) { q = brchain(p->link); if(a != ATEXT && a != ABCASE) if(q != P && (q->mark&FOLL)) { @@ -262,7 +178,7 @@ p->link = p->cond; p->cond = q; } - xfol(p->link); + xfol(p->link, last); q = brchain(p->cond); if(q == P) q = p->cond; @@ -280,7 +196,7 @@ void patch(void) { - long c, vexit; + int32 c, vexit; Prog *p, *q; Sym *s; int a; @@ -291,93 +207,51 @@ 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((a == ABL || a == AB || a == ARET) && - 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; - p->to.type = D_BRANCH; - break; - case SUNDEF: - if(p->as != ABL) - diag("help: SUNDEF in AB || ARET"); - p->to.offset = 0; - p->to.type = D_BRANCH; - p->cond = UP; - break; + for(cursym = textp; cursym != nil; cursym = cursym->next) { + for(p = cursym->text; p != P; p = p->link) { + a = p->as; + if((a == ABL || a == ABX || a == AB || a == ARET) && + p->to.type != D_BRANCH && p->to.sym != S) { + s = p->to.sym; + switch(s->type) { + default: + diag("undefined: %s", s->name); + s->type = STEXT; + s->value = vexit; + continue; // avoid more error messages + case STEXT: + p->to.offset = s->value; + p->to.type = D_BRANCH; + break; + } } + if(p->to.type != D_BRANCH) + continue; + c = p->to.offset; + for(q = textp->text; q != P;) { + if(c == q->pc) + break; + if(q->forwd != P && c >= q->forwd->pc) + q = q->forwd; + else + q = q->link; + } + if(q == P) { + diag("branch out of range %d\n%P", c, p); + p->to.type = D_NONE; + } + p->cond = q; } - if(p->to.type != D_BRANCH || p->cond == UP) - continue; - c = p->to.offset; - 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; - } - } -} - -#define LOG 5 -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; + for(cursym = textp; cursym != nil; cursym = cursym->next) { + for(p = cursym->text; p != P; p = p->link) { + if(p->cond != P) { + p->cond = brloop(p->cond); + if(p->cond != P) + if(p->to.type == D_BRANCH) + p->to.offset = p->cond->pc; + } } } } @@ -402,10 +276,10 @@ return P; } -long +int32 atolwhex(char *s) { - long n; + int32 n; int f; n = 0; @@ -442,10 +316,10 @@ return n; } -long -rnd(long v, long r) +int32 +rnd(int32 v, int32 r) { - long c; + int32 c; if(r <= 0) return v; @@ -456,140 +330,3 @@ v -= c; return v; } - -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=%ld\n", s->name, s->sig, 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); -} diff -r d8d00747375b sys/src/cmd/5l/prof.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/src/cmd/5l/prof.c Mon Nov 14 17:35:25 2011 +0100 @@ -0,0 +1,211 @@ +// Inferno utils/5l/obj.c +// http://code.google.com/p/inferno-os/source/browse/utils/5l/obj.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. + +// Profiling. + +#include "l.h" +#include "../ld/lib.h" + +void +doprof1(void) +{ +#ifdef NOTDEF // TODO(rsc) + Sym *s; + int32 n; + Prog *p, *q; + + if(debug['v']) + Bprint(&bso, "%5.2f profile 1\n", cputime()); + Bflush(&bso); + s = lookup("__mcount", 0); + n = 1; + for(p = firstp->link; p != P; p = p->link) { + if(p->as == ATEXT) { + q = prg(); + q->line = p->line; + q->link = datap; + datap = q; + q->as = ADATA; + q->from.type = D_OREG; + q->from.name = D_EXTERN; + q->from.offset = n*4; + q->from.sym = s; + q->reg = 4; + q->to = p->from; + q->to.type = D_CONST; + + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + p->as = AMOVW; + p->from.type = D_OREG; + p->from.name = D_EXTERN; + p->from.sym = s; + p->from.offset = n*4 + 4; + p->to.type = D_REG; + p->to.reg = REGTMP; + + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + p->as = AADD; + p->from.type = D_CONST; + p->from.offset = 1; + p->to.type = D_REG; + p->to.reg = REGTMP; + + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + p->as = AMOVW; + p->from.type = D_REG; + p->from.reg = REGTMP; + p->to.type = D_OREG; + p->to.name = D_EXTERN; + p->to.sym = s; + p->to.offset = n*4 + 4; + + n += 2; + continue; + } + } + q = prg(); + q->line = 0; + q->link = datap; + datap = q; + + q->as = ADATA; + q->from.type = D_OREG; + q->from.name = D_EXTERN; + q->from.sym = s; + q->reg = 4; + q->to.type = D_CONST; + q->to.offset = n; + + s->type = SBSS; + s->value = n*4; +#endif +} + +void +doprof2(void) +{ + Sym *s2, *s4; + Prog *p, *q, *ps2, *ps4; + + if(debug['v']) + Bprint(&bso, "%5.2f profile 2\n", cputime()); + Bflush(&bso); + s2 = lookup("_profin", 0); + s4 = lookup("_profout", 0); + if(s2->type != STEXT || s4->type != STEXT) { + diag("_profin/_profout not defined"); + return; + } + ps2 = P; + ps4 = P; + for(cursym = textp; cursym != nil; cursym = cursym->next) { + p = cursym->text; + if(cursym == s2) { + ps2 = p; + p->reg = 1; + } + if(cursym == s4) { + ps4 = p; + p->reg = 1; + } + } + for(cursym = textp; cursym != nil; cursym = cursym->next) + for(p = cursym->text; p != P; p = p->link) { + if(p->as == ATEXT) { + if(p->reg & NOPROF) { + for(;;) { + q = p->link; + if(q == P) + break; + if(q->as == ATEXT) + break; + p = q; + } + continue; + } + + /* + * BL profin, R2 + */ + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + p->as = ABL; + p->to.type = D_BRANCH; + p->cond = ps2; + p->to.sym = s2; + + continue; + } + if(p->as == ARET) { + /* + * RET + */ + q = prg(); + q->as = ARET; + q->from = p->from; + q->to = p->to; + q->link = p->link; + p->link = q; + + /* + * BL profout + */ + p->as = ABL; + p->from = zprg.from; + p->to = zprg.to; + p->to.type = D_BRANCH; + p->cond = ps4; + p->to.sym = s4; + + p = q; + + continue; + } + } +} diff -r d8d00747375b sys/src/cmd/5l/sched.c --- a/sys/src/cmd/5l/sched.c Thu Sep 29 03:00:00 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,645 +0,0 @@ -#include "l.h" - -enum -{ - E_PSR = 1<<0, - E_MEM = 1<<3, - E_MEMSP = 1<<4, /* uses offset and size */ - E_MEMSB = 1<<5, /* uses offset and size */ - ANYMEM = E_MEM|E_MEMSP|E_MEMSB, - DELAY = BRANCH|LOAD|FCMP, -}; - -typedef struct Sch Sch; -typedef struct Dep Dep; - -struct Dep -{ - ulong ireg; - ulong freg; - ulong cc; -}; -struct Sch -{ - Prog p; - Dep set; - Dep used; - long offset; - char size; - char nop; - char comp; -}; - -void regused(Sch*, Prog*); -int depend(Sch*, Sch*); -int conflict(Sch*, Sch*); -int offoverlap(Sch*, Sch*); -void dumpbits(Sch*, Dep*); - -void -sched(Prog *p0, Prog *pe) -{ - Prog *p, *q; - Sch sch[NSCHED], *s, *t, *u, *se, stmp; - - /* - * build side structure - */ - s = sch; - for(p=p0;; p=p->link) { - memset(s, 0, sizeof(*s)); - s->p = *p; - regused(s, p); - if(debug['X']) { - Bprint(&bso, "%P\t\tset", &s->p); - dumpbits(s, &s->set); - Bprint(&bso, "; used"); - dumpbits(s, &s->used); - if(s->comp) - Bprint(&bso, "; compound"); - if(s->p.mark & LOAD) - Bprint(&bso, "; load"); - if(s->p.mark & BRANCH) - Bprint(&bso, "; branch"); - if(s->p.mark & FCMP) - Bprint(&bso, "; fcmp"); - Bprint(&bso, "\n"); - } - if(p == pe) - break; - s++; - } - se = s; - - /* - * prepass to move things around - * does nothing, but tries to make - * the actual scheduler work better - */ - for(s=sch; s<=se; s++) { - if(!(s->p.mark & LOAD)) - continue; - /* always good to put nonconflict loads together */ - for(t=s+1; t<=se; t++) { - if(!(t->p.mark & LOAD)) - continue; - if(t->p.mark & BRANCH) - break; - if(conflict(s, t)) - break; - for(u=t-1; u>s; u--) - if(depend(u, t)) - goto no11; - u = s+1; - stmp = *t; - memmove(s+2, u, (uchar*)t - (uchar*)u); - *u = stmp; - break; - } - no11: - - /* put schedule fodder above load */ - for(t=s+1; t<=se; t++) { - if(t->p.mark & BRANCH) - break; - if(s > sch && conflict(s-1, t)) - continue; - for(u=t-1; u>=s; u--) - if(depend(t, u)) - goto no1; - stmp = *t; - memmove(s+1, s, (uchar*)t - (uchar*)s); - *s = stmp; - if(!(s->p.mark & LOAD)) - break; - no1:; - } - } - - for(s=se; s>=sch; s--) { - if(!(s->p.mark & DELAY)) - continue; - if(s < se) - if(!conflict(s, s+1)) - goto out3; - /* - * s is load, s+1 is immediate use of result or end of block - * t is the trial instruction to insert between s and s+1 - */ - if(!debug['Y']) - for(t=s-1; t>=sch; t--) { - if(t->comp) - if(s->p.mark & BRANCH) - goto no2; - if(t->p.mark & DELAY) - if(s >= se || conflict(t, s+1)) - goto no2; - for(u=t+1; u<=s; u++) - if(depend(u, t)) - goto no2; - goto out2; - no2:; - } - if(debug['X']) - Bprint(&bso, "?l%P\n", &s->p); - s->nop = 1; - if(debug['v']) { - if(s->p.mark & LOAD) { - nop.load.count++; - nop.load.outof++; - } - if(s->p.mark & BRANCH) { - nop.branch.count++; - nop.branch.outof++; - } - if(s->p.mark & FCMP) { - nop.fcmp.count++; - nop.fcmp.outof++; - } - } - continue; - - out2: - if(debug['X']) { - Bprint(&bso, "!l%P\n", &t->p); - Bprint(&bso, "%P\n", &s->p); - } - stmp = *t; - memmove(t, t+1, (uchar*)s - (uchar*)t); - *s = stmp; - s--; - - out3: - if(debug['v']) { - if(s->p.mark & LOAD) - nop.load.outof++; - if(s->p.mark & BRANCH) - nop.branch.outof++; - if(s->p.mark & FCMP) - nop.fcmp.outof++; - } - } - - /* Avoid HI/LO use->set */ - t = sch+1; - for(s=sch; sused.cc & E_PSR) == 0) - continue; - if(t->set.cc & E_PSR) - s->nop = 2; - } - - /* - * put it all back - */ - for(s=sch, p=p0; s<=se; s++, p=q) { - q = p->link; - if(q != s->p.link) { - *p = s->p; - p->link = q; - } - while(s->nop--) - addnop(p); - } - if(debug['X']) { - Bprint(&bso, "\n"); - Bflush(&bso); - } -} - -void -regused(Sch *s, Prog *realp) -{ - int c, ar, ad, ld, sz; - ulong m; - Prog *p; - - p = &s->p; - s->comp = compound(p); - s->nop = 0; - if(s->comp) { - s->set.ireg |= 1<used.ireg |= 1<as) { - case ATEXT: - curtext = realp; - autosize = p->to.offset + 4; - ad = 1; - break; - case ABL: - c = p->reg; - if(c == NREG) - c = REGLINK; - s->set.ireg |= 1<set.cc |= E_PSR; - p->mark |= FCMP; - break; - case AB: - ar = 1; - ad = 1; - break; - case AMOVB: - case AMOVBU: - sz = 1; - ld = 1; - break; - case AMOVH: - case AMOVHU: - sz = 2; - ld = 1; - break; - case AMOVF: - case AMOVW: - sz = 4; - ld = 1; - break; - case AMOVD: - sz = 8; - ld = 1; - break; - case ADIV: - case ADIVU: - case AMUL: - case AMULU: - case AMOD: - case AMODU: - - case AADD: - case AAND: - case ANOR: - case AORR: - case ASLL: - case ASRA: - case ASRL: - case ASUB: - case AEOR: - - case AADDD: - case AADDF: - case ASUBD: - case ASUBF: - case AMULF: - case AMULD: - case ADIVF: - if(p->reg == NREG) { - if(p->to.type == D_REG || p->to.type == D_FREG) - p->reg = p->to.reg; - if(p->reg == NREG) - print("botch %P\n", p); - } - break; - } - -/* - * flags based on 'to' field - */ - c = p->to.class; - if(c == 0) { - c = aclass(&p->to) + 1; - p->to.class = c; - } - c--; - switch(c) { - default: - print("unknown class %d %D\n", c, &p->to); - - case C_ZCON: - case C_ICON: - case C_SCON: - case C_SICON: - case C_LCON: - case C_NONE: - case C_SBRA: - case C_LBRA: - break; - - case C_PSR: - s->set.cc |= E_PSR; - break; - case C_ZOREG: - case C_SOREG: - case C_LOREG: - c = p->to.reg; - s->used.ireg |= 1<size = sz; - s->offset = regoff(&p->to); - - m = ANYMEM; - if(c == REGSB) - m = E_MEMSB; - if(c == REGSP) - m = E_MEMSP; - - if(ar) - s->used.cc |= m; - else - s->set.cc |= m; - break; - case C_SACON: - case C_LACON: - s->used.ireg |= 1<used.ireg |= 1<used.ireg |= 1<to.reg; - else - s->set.ireg |= 1<to.reg; - break; - case C_REGREG: - if(ar){ - s->used.ireg |= 1<to.reg; - s->used.ireg |= 1<to.offset; - }else{ - s->set.ireg |= 1<to.reg; - s->set.ireg |= 1<to.offset; - } - break; - case C_FREG: - /* do better -- determine double prec */ - if(ar) { - s->used.freg |= 1<to.reg; - s->used.freg |= 1<<(p->to.reg|1); - } else { - s->set.freg |= 1<to.reg; - s->set.freg |= 1<<(p->to.reg|1); - } - if(ld && p->from.type == D_REG) - p->mark |= LOAD; - break; - case C_SAUTO: - case C_LAUTO: - s->used.ireg |= 1<size = sz; - s->offset = regoff(&p->to); - - if(ar) - s->used.cc |= E_MEMSP; - else - s->set.cc |= E_MEMSP; - break; - case C_SEXT: - case C_LEXT: - s->used.ireg |= 1<size = sz; - s->offset = regoff(&p->to); - - if(ar) - s->used.cc |= E_MEMSB; - else - s->set.cc |= E_MEMSB; - break; - } - -/* - * flags based on 'from' field - */ - c = p->from.class; - if(c == 0) { - c = aclass(&p->from) + 1; - p->from.class = c; - } - c--; - switch(c) { - default: - print("unknown class %d %D\n", c, &p->from); - - case C_ZCON: - case C_ICON: - case C_SCON: - case C_SICON: - case C_LCON: - case C_NONE: - case C_SBRA: - case C_LBRA: - break; - case C_PSR: - s->used.cc |= E_PSR; - break; - case C_ZOREG: - case C_SOREG: - case C_LOREG: - c = p->from.reg; - s->used.ireg |= 1<mark |= LOAD; - s->size = sz; - s->offset = regoff(&p->from); - - m = ANYMEM; - if(c == REGSB) - m = E_MEMSB; - if(c == REGSP) - m = E_MEMSP; - - s->used.cc |= m; - break; - case C_SACON: - case C_LACON: - s->used.ireg |= 1<used.ireg |= 1<used.ireg |= 1<from.reg; - break; - case C_REGREG: - s->used.ireg |= 1<from.reg; - s->used.ireg |= 1<from.offset; - break; - case C_FREG: - /* do better -- determine double prec */ - s->used.freg |= 1<from.reg; - s->used.freg |= 1<<(p->from.reg|1); - if(ld && p->to.type == D_REG) - p->mark |= LOAD; - break; - case C_SAUTO: - case C_LAUTO: - s->used.ireg |= 1<mark |= LOAD; - if(ad) - break; - s->size = sz; - s->offset = regoff(&p->from); - - s->used.cc |= E_MEMSP; - break; - case C_SEXT: - case C_LEXT: - s->used.ireg |= 1<mark |= LOAD; - if(ad) - break; - s->size = sz; - s->offset = regoff(&p->from); - - s->used.cc |= E_MEMSB; - break; - } - - c = p->reg; - if(c != NREG) { - if(p->from.type == D_FREG || p->to.type == D_FREG) { - s->used.freg |= 1<used.freg |= 1<<(c|1); - } else - s->used.ireg |= 1<set.ireg & (sb->set.ireg|sb->used.ireg)) - return 1; - if(sb->set.ireg & sa->used.ireg) - return 1; - - if(sa->set.freg & (sb->set.freg|sb->used.freg)) - return 1; - if(sb->set.freg & sa->used.freg) - return 1; - - /* - * special case. - * loads from same address cannot pass. - * this is for hardware fifo's and the like - */ - if(sa->used.cc & sb->used.cc & E_MEM) - if(sa->p.reg == sb->p.reg) - if(regoff(&sa->p.from) == regoff(&sb->p.from)) - return 1; - - x = (sa->set.cc & (sb->set.cc|sb->used.cc)) | - (sb->set.cc & sa->used.cc); - if(x) { - /* - * allow SB and SP to pass each other. - * allow SB to pass SB iff doffsets are ok - * anything else conflicts - */ - if(x != E_MEMSP && x != E_MEMSB) - return 1; - x = sa->set.cc | sb->set.cc | - sa->used.cc | sb->used.cc; - if(x & E_MEM) - return 1; - if(offoverlap(sa, sb)) - return 1; - } - - return 0; -} - -int -offoverlap(Sch *sa, Sch *sb) -{ - - if(sa->offset < sb->offset) { - if(sa->offset+sa->size > sb->offset) - return 1; - return 0; - } - if(sb->offset+sb->size > sa->offset) - return 1; - return 0; -} - -/* - * test 2 adjacent instructions - * and find out if inserted instructions - * are desired to prevent stalls. - */ -int -conflict(Sch *sa, Sch *sb) -{ - - if(sa->set.ireg & sb->used.ireg) - return 1; - if(sa->set.freg & sb->used.freg) - return 1; - if(sa->set.cc & sb->used.cc) - return 1; - - return 0; -} - -int -compound(Prog *p) -{ - Optab *o; - - o = oplook(p); - if(o->size != 4) - return 1; - if(p->to.type == D_REG && p->to.reg == REGSB) - return 1; - return 0; -} - -void -dumpbits(Sch *s, Dep *d) -{ - int i; - - for(i=0; i<32; i++) - if(d->ireg & (1<freg & (1<cc & (1<size); - break; - case E_MEMSB: - Bprint(&bso, " SB%d", s->size); - break; - case E_MEMSP: - Bprint(&bso, " SP%d", s->size); - break; - } -} diff -r d8d00747375b sys/src/cmd/5l/softfloat.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/src/cmd/5l/softfloat.c Mon Nov 14 17:35:25 2011 +0100 @@ -0,0 +1,88 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "l.h" +#include "../ld/lib.h" + +// Software floating point. + +void +softfloat(void) +{ + Prog *p, *next, *psfloat; + Sym *symsfloat; + int wasfloat; + + if(!debug['F']) + return; + + symsfloat = lookup("_sfloat", 0); + psfloat = P; + if(symsfloat->type == STEXT) + psfloat = symsfloat->text; + + for(cursym = textp; cursym != nil; cursym = cursym->next) { + wasfloat = 0; + for(p = cursym->text; p != P; p = p->link) + if(p->cond != P) + p->cond->mark |= LABEL; + for(p = cursym->text; p != P; p = p->link) { + switch(p->as) { + case AMOVW: + if(p->to.type == D_FREG || p->from.type == D_FREG) + goto soft; + goto notsoft; + + case AMOVWD: + case AMOVWF: + case AMOVDW: + case AMOVFW: + case AMOVFD: + case AMOVDF: + case AMOVF: + case AMOVD: + + case ACMPF: + case ACMPD: + case AADDF: + case AADDD: + case ASUBF: + case ASUBD: + case AMULF: + case AMULD: + case ADIVF: + case ADIVD: + case ASQRTF: + case ASQRTD: + goto soft; + + default: + goto notsoft; + + soft: + if (psfloat == P) + diag("floats used with _sfloat not defined"); + if (!wasfloat || (p->mark&LABEL)) { + next = prg(); + *next = *p; + + // BL _sfloat(SB) + *p = zprg; + p->link = next; + p->as = ABL; + p->to.type = D_BRANCH; + p->to.sym = symsfloat; + p->cond = psfloat; + + p = next; + wasfloat = 1; + } + break; + + notsoft: + wasfloat = 0; + } + } + } +} diff -r d8d00747375b sys/src/cmd/5l/span.c --- a/sys/src/cmd/5l/span.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/5l/span.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,21 +1,95 @@ +// Inferno utils/5l/span.c +// http://code.google.com/p/inferno-os/source/browse/utils/5l/span.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. + +// Instruction layout. + #include "l.h" +#include "../ld/lib.h" static struct { - ulong start; - ulong size; + uint32 start; + uint32 size; + uint32 extra; } pool; -void checkpool(Prog*); -void flushpool(Prog*, int); +int checkpool(Prog*, int); +int flushpool(Prog*, int, int); + +int +isbranch(Prog *p) +{ + int as = p->as; + return (as >= ABEQ && as <= ABLE) || as == AB || as == ABL || as == ABX; +} + +static int +scan(Prog *op, Prog *p, int c) +{ + Prog *q; + + for(q = op->link; q != p && q != P; q = q->link){ + q->pc = c; + c += oplook(q)->size; + nocache(q); + } + return c; +} + +/* size of a case statement including jump table */ +static int32 +casesz(Prog *p) +{ + int jt = 0; + int32 n = 0; + Optab *o; + + for( ; p != P; p = p->link){ + if(p->as == ABCASE) + jt = 1; + else if(jt) + break; + o = oplook(p); + n += o->size; + } + return n; +} void span(void) { - Prog *p; - Sym *setext, *s; + Prog *p, *op; Optab *o; - int m, bflag, i; - long c, otxt, v; + int m, bflag, i, v; + int32 c, otxt, out[6]; + Section *sect; + uchar *bp; if(debug['v']) Bprint(&bso, "%5.2f span\n", cputime()); @@ -24,42 +98,54 @@ bflag = 0; c = INITTEXT; otxt = c; - for(p = firstp; p != P; p = p->link) { + for(cursym = textp; cursym != nil; cursym = cursym->next) { + p = cursym->text; p->pc = c; - o = oplook(p); - m = o->size; - if(m == 0) { - if(p->as == ATEXT) { - curtext = p; - autosize = p->to.offset + 4; - if(p->from.sym != S) - p->from.sym->value = c; - /* need passes to resolve branches */ - if(c-otxt >= 1L<<17) - bflag = 1; - otxt = c; + cursym->value = c; + + autosize = p->to.offset + 4; + if(p->from.sym != S) + p->from.sym->value = c; + /* need passes to resolve branches */ + if(c-otxt >= 1L<<17) + bflag = 1; + otxt = c; + + for(op = p, p = p->link; p != P; op = p, p = p->link) { + curp = p; + p->pc = c; + o = oplook(p); + m = o->size; + // must check literal pool here in case p generates many instructions + if(blitrl){ + if(checkpool(op, p->as == ACASE ? casesz(p) : m)) + c = p->pc = scan(op, p, c); + } + if(m == 0) { + diag("zero-width instruction\n%P", p); continue; } - diag("zero-width instruction\n%P", p); - continue; + switch(o->flag & (LFROM|LTO|LPOOL)) { + case LFROM: + addpool(p, &p->from); + break; + case LTO: + addpool(p, &p->to); + break; + case LPOOL: + if ((p->scond&C_SCOND) == 14) + flushpool(p, 0, 0); + break; + } + if(p->as==AMOVW && p->to.type==D_REG && p->to.reg==REGPC && (p->scond&C_SCOND) == 14) + flushpool(p, 0, 0); + c += m; } - switch(o->flag & (LFROM|LTO|LPOOL)) { - case LFROM: - addpool(p, &p->from); - break; - case LTO: - addpool(p, &p->to); - break; - case LPOOL: - if ((p->scond&C_SCOND) == 14) - flushpool(p, 0); - break; + if(blitrl){ + if(checkpool(op, 0)) + c = scan(op, P, c); } - if(p->as==AMOVW && p->to.type==D_REG && p->to.reg==REGPC && (p->scond&C_SCOND) == 14) - flushpool(p, 0); - c += m; - if(blitrl) - checkpool(p); + cursym->size = c - cursym->value; } /* @@ -73,77 +159,85 @@ Bprint(&bso, "%5.2f span1\n", cputime()); bflag = 0; c = INITTEXT; - for(p = firstp; p != P; p = p->link) { - p->pc = c; - o = oplook(p); -/* very larg branches - if(o->type == 6 && p->cond) { - otxt = p->cond->pc - c; - if(otxt < 0) - otxt = -otxt; - if(otxt >= (1L<<17) - 10) { - q = prg(); - q->link = p->link; - p->link = q; - q->as = AB; - q->to.type = D_BRANCH; - q->cond = p->cond; - p->cond = q; - q = prg(); - q->link = p->link; - p->link = q; - q->as = AB; - q->to.type = D_BRANCH; - q->cond = q->link->link; - bflag = 1; + for(cursym = textp; cursym != nil; cursym = cursym->next) { + cursym->value = c; + for(p = cursym->text; p != P; p = p->link) { + curp = p; + p->pc = c; + o = oplook(p); +/* very large branches + if(o->type == 6 && p->cond) { + otxt = p->cond->pc - c; + if(otxt < 0) + otxt = -otxt; + if(otxt >= (1L<<17) - 10) { + q = prg(); + q->link = p->link; + p->link = q; + q->as = AB; + q->to.type = D_BRANCH; + q->cond = p->cond; + p->cond = q; + q = prg(); + q->link = p->link; + p->link = q; + q->as = AB; + q->to.type = D_BRANCH; + q->cond = q->link->link; + bflag = 1; + } } - } */ - m = o->size; - if(m == 0) { - if(p->as == ATEXT) { - curtext = p; - autosize = p->to.offset + 4; - if(p->from.sym != S) - p->from.sym->value = c; + m = o->size; + if(m == 0) { + if(p->as == ATEXT) { + autosize = p->to.offset + 4; + if(p->from.sym != S) + p->from.sym->value = c; + continue; + } + diag("zero-width instruction\n%P", p); continue; } - diag("zero-width instruction\n%P", p); - continue; + c += m; } - c += m; - } - } - - if(debug['t']) { - /* - * add strings to text segment - */ - c = rnd(c, 8); - for(i=0; ilink) { - if(s->type != SSTRING) - continue; - v = s->value; - while(v & 3) - v++; - s->value = c; - c += v; + cursym->size = c - cursym->value; } } c = rnd(c, 8); - - setext = lookup("etext", 0); - if(setext != S) { - setext->value = c; - textsize = c - INITTEXT; + + /* + * lay out the code. all the pc-relative code references, + * even cross-function, are resolved now; + * only data references need to be relocated. + * with more work we could leave cross-function + * code references to be relocated too, and then + * perhaps we'd be able to parallelize the span loop above. + */ + for(cursym = textp; cursym != nil; cursym = cursym->next) { + p = cursym->text; + autosize = p->to.offset + 4; + symgrow(cursym, cursym->size); + + bp = cursym->p; + for(p = p->link; p != P; p = p->link) { + pc = p->pc; + curp = p; + o = oplook(p); + asmout(p, o, out); + for(i=0; isize/4; i++) { + v = out[i]; + *bp++ = v; + *bp++ = v>>8; + *bp++ = v>>16; + *bp++ = v>>24; + } + } } - if(INITRND) - INITDAT = rnd(c, INITRND); - if(debug['v']) - Bprint(&bso, "tsize = %lux\n", textsize); - Bflush(&bso); + sect = addsection(&segtext, ".text", 05); + sect->vaddr = INITTEXT; + sect->len = c - INITTEXT; } /* @@ -152,24 +246,24 @@ * drop the pool now, and branch round it. * this happens only in extended basic blocks that exceed 4k. */ -void -checkpool(Prog *p) +int +checkpool(Prog *p, int sz) { - if(pool.size >= 0xffc || immaddr((p->pc+4)+4+pool.size - pool.start+8) == 0) - flushpool(p, 1); + if(pool.size >= 0xffc || immaddr((p->pc+sz+4)+4+pool.size - pool.start+8) == 0) + return flushpool(p, 1, 0); else if(p->link == P) - flushpool(p, 2); + return flushpool(p, 2, 0); + return 0; } -void -flushpool(Prog *p, int skip) +int +flushpool(Prog *p, int skip, int force) { Prog *q; if(blitrl) { if(skip){ - if(debug['v'] && skip == 1) - print("note: flush literal pool at %lux: len=%lud ref=%lux\n", p->pc+4, pool.size, pool.start); + if(0 && skip==1)print("note: flush literal pool at %ux: len=%ud ref=%ux\n", p->pc+4, pool.size, pool.start); q = prg(); q->as = AB; q->to.type = D_BRANCH; @@ -177,15 +271,18 @@ q->link = blitrl; blitrl = q; } - else if(p->pc+pool.size-pool.start < 2048) - return; + else if(!force && (p->pc+pool.size-pool.start < 2048)) + return 0; elitrl->link = p->link; p->link = blitrl; blitrl = 0; /* BUG: should refer back to values until out-of-range */ elitrl = 0; pool.size = 0; pool.start = 0; + pool.extra = 0; + return 1; } + return 0; } void @@ -204,11 +301,12 @@ t.to = *a; break; - case C_SROREG: + case C_SROREG: case C_LOREG: case C_ROREG: case C_FOREG: case C_SOREG: + case C_HOREG: case C_FAUTO: case C_SAUTO: case C_LAUTO: @@ -231,6 +329,7 @@ if(blitrl == P) { blitrl = q; pool.start = p->pc; + q->align = 4; } else elitrl->link = q; elitrl = q; @@ -240,18 +339,18 @@ } void -xdefine(char *p, int t, long v) +xdefine(char *p, int t, int32 v) { Sym *s; s = lookup(p, 0); - if(s->type == 0 || s->type == SXREF) { - s->type = t; - s->value = v; - } + s->type = t; + s->value = v; + s->reachable = 1; + s->special = 1; } -long +int32 regoff(Adr *a) { @@ -260,8 +359,8 @@ return instoffset; } -long -immrot(ulong v) +int32 +immrot(uint32 v) { int i; @@ -273,8 +372,8 @@ return 0; } -long -immaddr(long v) +int32 +immaddr(int32 v) { if(v >= 0 && v <= 0xfff) return (v & 0xfff) | @@ -287,13 +386,13 @@ } int -immfloat(long v) +immfloat(int32 v) { return (v & 0xC03) == 0; /* offset will fit in floating-point load/store */ } int -immhalf(long v) +immhalf(int32 v) { if(v >= 0 && v <= 0xff) return v| @@ -305,6 +404,28 @@ return 0; } +int32 +symaddr(Sym *s) +{ + int32 v; + + v = s->value; + switch(s->type) { + default: + diag("unexpected type %d in symaddr(%s)", s->type, s->name); + return 0; + + case STEXT: + case SELFROSECT: + case SRODATA: + case SDATA: + case SBSS: + case SCONST: + break; + } + return v; +} + int aclass(Adr *a) { @@ -339,38 +460,9 @@ print("%D\n", a); return C_GOK; } - s = a->sym; - t = s->type; - if(t == 0 || t == SXREF) { - diag("undefined external: %s in %s", - s->name, TNAME); - s->type = SDATA; - } - if(dlm) { - switch(t) { - default: - instoffset = s->value + a->offset + INITDAT; - break; - case SUNDEF: - case STEXT: - case SCONST: - case SLEAF: - case SSTRING: - instoffset = s->value + a->offset; - break; - } - return C_ADDR; - } - instoffset = s->value + a->offset - BIG; - t = immaddr(instoffset); - if(t) { - if(immhalf(instoffset)) - return immfloat(t) ? C_HFEXT : C_HEXT; - if(immfloat(t)) - return C_FEXT; - return C_SEXT; - } - return C_LEXT; + instoffset = 0; // s.b. unused but just in case + return C_ADDR; + case D_AUTO: instoffset = autosize + a->offset; t = immaddr(instoffset); @@ -423,24 +515,20 @@ switch(a->name) { case D_EXTERN: case D_STATIC: - s = a->sym; - t = s->type; - if(t == 0 || t == SXREF) { - diag("undefined external: %s in %s", - s->name, TNAME); - s->type = SDATA; - } - instoffset = s->value + a->offset + INITDAT; - if(s->type == STEXT || s->type == SLEAF || s->type == SUNDEF) - instoffset = s->value + a->offset; - return C_LCON; + instoffset = 0; // s.b. unused but just in case + return C_ADDR; } return C_GOK; case D_FCONST: - return C_FCON; + if(chipzero(&a->ieee) >= 0) + return C_ZFCON; + if(chipfloat(&a->ieee) >= 0) + return C_SFCON; + return C_LFCON; case D_CONST: + case D_CONST2: switch(a->name) { case D_NONE: @@ -461,29 +549,7 @@ s = a->sym; if(s == S) break; - t = s->type; - switch(t) { - case 0: - case SXREF: - diag("undefined external: %s in %s", - s->name, TNAME); - s->type = SDATA; - break; - case SUNDEF: - case STEXT: - case SSTRING: - case SCONST: - case SLEAF: - instoffset = s->value + a->offset; - return C_LCON; - } - if(!dlm) { - instoffset = s->value + a->offset - BIG; - t = immrot(instoffset); - if(t && instoffset != 0) - return C_RECON; - } - instoffset = s->value + a->offset + INITDAT; + instoffset = 0; // s.b. unused but just in case return C_LCON; case D_AUTO: @@ -541,8 +607,8 @@ } o = oprange[r].stop; /* just generate an error */ } - if(0) { - print("oplook %A %d %d %d\n", + if(debug['O']) { + print("oplook %A %O %O %O\n", (int)p->as, a1, a2, a3); print(" %d %d\n", p->from.type, p->to.type); } @@ -556,8 +622,8 @@ p->optab = (o-optab)+1; return o; } - diag("illegal combination %A %d %d %d", - p->as, a1, a2, a3); + diag("illegal combination %A %O %O %O, %d %d", + p->as, a1, a2, a3, p->from.type, p->to.type); prasm(p); if(o == 0) o = optab; @@ -579,21 +645,11 @@ if(b == C_RACON) return 1; break; - case C_LECON: - if(b == C_RECON) + case C_LFCON: + if(b == C_ZFCON || b == C_SFCON) return 1; break; - case C_HFEXT: - return b == C_HEXT || b == C_FEXT; - case C_FEXT: - case C_HEXT: - return b == C_HFEXT; - case C_SEXT: - return cmp(C_HFEXT, b); - case C_LEXT: - return cmp(C_SEXT, b); - case C_HFAUTO: return b == C_HAUTO || b == C_FAUTO; case C_FAUTO: @@ -621,6 +677,10 @@ if(b == C_SBRA) return 1; break; + + case C_HREG: + return cmp(C_SP, b) || cmp(C_PC, b); + } return 0; } @@ -636,9 +696,6 @@ n = p1->as - p2->as; if(n) return n; - n = (p2->flag&V4) - (p1->flag&V4); /* architecture version */ - if(n) - return n; n = p1->a1 - p2->a1; if(n) return n; @@ -656,15 +713,11 @@ { int i, n, r; - armv4 = !debug['h']; for(i=0; it; - r->t += 64; - m = r->m; - a = r->a; - r->m = nm = malloc(r->t*sizeof(uchar)); - r->a = na = malloc(r->t*sizeof(ulong)); - memmove(nm, m, t*sizeof(uchar)); - memmove(na, a, t*sizeof(ulong)); - free(m); - free(a); -} - -void -dynreloc(Sym *s, long v, int abs) -{ - int i, k, n; - uchar *m; - ulong *a; - Reloc *r; - - if(v&3) - diag("bad relocation address"); - v >>= 2; - if(s != S && s->type == SUNDEF) - k = abs ? ABSU : RELU; - else - k = abs ? ABSD : RELD; - /* Bprint(&bso, "R %s a=%ld(%lx) %d\n", s->name, a, a, k); */ - k = modemap[k]; - r = &rels; - n = r->n; - if(n >= r->t) - grow(r); - m = r->m; - a = r->a; - for(i = n; i > 0; i--){ - if(v < a[i-1]){ /* happens occasionally for data */ - m[i] = m[i-1]; - a[i] = a[i-1]; - } - else - break; - } - m[i] = k; - a[i] = v; - r->n++; -} - -static int -sput(char *s) -{ - char *p; - - p = s; - while(*s) - cput(*s++); - cput(0); - return s-p+1; -} - -void -asmdyn() -{ - int i, n, t, c; - Sym *s; - ulong la, ra, *a; - vlong off; - uchar *m; - Reloc *r; - - cflush(); - off = seek(cout, 0, 1); - lput(0); - t = 0; - lput(imports); - t += 4; - for(i = 0; i < NHASH; i++) - for(s = hash[i]; s != S; s = s->link) - if(s->type == SUNDEF){ - lput(s->sig); - t += 4; - t += sput(s->name); - } - - la = 0; - r = &rels; - n = r->n; - m = r->m; - a = r->a; - lput(n); - t += 4; - for(i = 0; i < n; i++){ - ra = *a-la; - if(*a < la) - diag("bad relocation order"); - if(ra < 256) - c = 0; - else if(ra < 65536) - c = 1; - else - c = 2; - cput((c<<6)|*m++); - t++; - if(c == 0){ - cput(ra); - t++; - } - else if(c == 1){ - wput(ra); - t += 2; - } - else{ - lput(ra); - t += 4; - } - la = *a++; - } - - cflush(); - seek(cout, off, 0); - lput(t); - - if(debug['v']){ - Bprint(&bso, "import table entries = %d\n", imports); - Bprint(&bso, "export table entries = %d\n", exports); - } -} diff -r d8d00747375b sys/src/cmd/6a/a.h --- a/sys/src/cmd/6a/a.h Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/6a/a.h Mon Nov 14 17:35:25 2011 +0100 @@ -1,28 +1,63 @@ -#include -#include +// Inferno utils/6a/a.h +// http://code.google.com/p/inferno-os/source/browse/utils/6a/a.h +// +// 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 -#include "../6c/6.out.h" +#include "../6l/6.out.h" #ifndef EXTERN #define EXTERN extern #endif +#undef getc +#undef ungetc +#undef BUFSIZ + +#define getc ccgetc +#define ungetc ccungetc + typedef struct Sym Sym; typedef struct Ref Ref; typedef struct Gen Gen; typedef struct Io Io; typedef struct Hist Hist; -typedef struct Gen2 Gen2; +typedef struct Gen2 Gen2; #define MAXALIGN 7 #define FPCHIP 1 #define NSYMB 500 #define BUFSIZ 8192 #define HISTSZ 20 -#define NINCLUDE 10 -#define NHUNK 10000 +#ifndef EOF #define EOF (-1) +#endif #define IGN (-2) #define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff) #define NHASH 503 @@ -88,7 +123,7 @@ { Hist* link; char* name; - long line; + int32 line; vlong offset; }; #define H ((Hist*)0) @@ -104,34 +139,38 @@ EXTERN char debug[256]; EXTERN Sym* hash[NHASH]; -EXTERN char* Dlist[30]; +EXTERN char** Dlist; EXTERN int nDlist; EXTERN Hist* ehist; EXTERN int newflag; EXTERN Hist* hist; EXTERN char* hunk; -EXTERN char* include[NINCLUDE]; +EXTERN char** include; EXTERN Io* iofree; EXTERN Io* ionext; EXTERN Io* iostack; -EXTERN long lineno; +EXTERN int32 lineno; EXTERN int nerrors; -EXTERN long nhunk; +EXTERN int32 nhunk; EXTERN int ninclude; +EXTERN int32 nsymb; EXTERN Gen nullgen; EXTERN char* outfile; EXTERN int pass; EXTERN char* pathname; -EXTERN long pc; +EXTERN int32 pc; EXTERN int peekc; +EXTERN int32 stmtline; EXTERN int sym; -EXTERN char symb[NSYMB]; +EXTERN char* symb; EXTERN int thechar; EXTERN char* thestring; -EXTERN long thunk; +EXTERN int32 thunk; EXTERN Biobuf obuf; -void* allocn(void*, long, long); +void* alloc(int32); +void* allocn(void*, int32, int32); +void ensuresymb(int32); void errorexit(void); void pushio(void); void newio(void); @@ -139,7 +178,7 @@ Sym* slookup(char*); Sym* lookup(void); void syminit(Sym*); -long yylex(void); +int32 yylex(void); int getc(void); int getnsc(void); void unget(int); @@ -166,30 +205,10 @@ void macif(int); void macend(void); void dodefine(char*); -void prfile(long); +void prfile(int32); void linehist(char*, int); void gethunk(void); void yyerror(char*, ...); int yyparse(void); void setinclude(char*); int assemble(char*); - -/* - * Posix.c/Inferno.c/Nt.c - */ -enum /* keep in synch with ../cc/cc.h */ -{ - Plan9 = 1<<0, - Unix = 1<<1, - Windows = 1<<2 -}; -int mywait(int*); -int mycreat(char*, int); -int systemtype(int); -int pathchar(void); -char* mygetwd(char*, int); -int myexec(char*, char*[]); -int mydup(int, int); -int myfork(void); -int mypipe(int*); -void* mysbrk(ulong); diff -r d8d00747375b sys/src/cmd/6a/a.y --- a/sys/src/cmd/6a/a.y Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/6a/a.y Mon Nov 14 17:35:25 2011 +0100 @@ -1,4 +1,37 @@ +// Inferno utils/6a/a.y +// http://code.google.com/p/inferno-os/source/browse/utils/6a/a.y +// +// 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 +#include /* if we don't, bison will, and a.h re-#defines getc */ +#include #include "a.h" %} %union { @@ -16,19 +49,24 @@ %left '+' '-' %left '*' '/' '%' %token LTYPE0 LTYPE1 LTYPE2 LTYPE3 LTYPE4 -%token LTYPEC LTYPED LTYPEN LTYPER LTYPET LTYPES LTYPEM LTYPEI LTYPEXC LTYPEX LTYPERT +%token LTYPEC LTYPED LTYPEN LTYPER LTYPET LTYPEG +%token LTYPES LTYPEM LTYPEI LTYPEXC LTYPEX LTYPERT %token LCONST LFP LPC LSB %token LBREG LLREG LSREG LFREG LMREG LXREG %token LFCONST %token LSCONST LSP %token LNAME LLAB LVAR -%type con expr pointer offset -%type mem imm reg nam rel rem rim rom omem nmem -%type nonnon nonrel nonrem rimnon rimrem remrim spec10 +%type con con2 expr pointer offset +%type mem imm imm2 reg nam rel rem rim rom omem nmem +%type nonnon nonrel nonrem rimnon rimrem remrim spec10 spec11 %type spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8 spec9 %% prog: -| prog line +| prog + { + stmtline = lineno; + } + line line: LLAB ':' @@ -76,6 +114,7 @@ | LTYPEXC spec8 { outcode($1, &$2); } | LTYPEX spec9 { outcode($1, &$2); } | LTYPERT spec10 { outcode($1, &$2); } +| LTYPEG spec11 { outcode($1, &$2); } nonnon: { @@ -147,12 +186,12 @@ } spec2: /* TEXT */ - mem ',' imm + mem ',' imm2 { $$.from = $1; $$.to = $3; } -| mem ',' con ',' imm +| mem ',' con ',' imm2 { $$.from = $1; $$.from.scale = $3; @@ -227,7 +266,7 @@ { $$.from = $1; $$.to = $3; - $$.from.offset = $5; + $$.to.offset = $5; } spec9: /* shufl */ @@ -251,6 +290,19 @@ $$.to = nullgen; } +spec11: /* GLOBL */ + mem ',' imm + { + $$.from = $1; + $$.to = $3; + } +| mem ',' con ',' imm + { + $$.from = $1; + $$.from.scale = $3; + $$.to = $5; + } + rem: reg | mem @@ -333,6 +385,13 @@ $$ = nullgen; $$.type = $1; } +imm2: + '$' con2 + { + $$ = nullgen; + $$.type = D_CONST; + $$.offset = $2; + } imm: '$' con @@ -370,6 +429,12 @@ $$.type = D_FCONST; $$.dval = $3; } +| '$' '(' '-' LFCONST ')' + { + $$ = nullgen; + $$.type = D_FCONST; + $$.dval = -$4; + } | '$' '-' LFCONST { $$ = nullgen; @@ -400,6 +465,12 @@ $$.type = D_INDIR+D_SP; $$.offset = $1; } +| con '(' LSREG ')' + { + $$ = nullgen; + $$.type = D_INDIR+$3; + $$.offset = $1; + } | con '(' LLREG '*' con ')' { $$ = nullgen; @@ -518,6 +589,26 @@ $$ = $2; } +con2: + LCONST + { + $$ = $1 & 0xffffffffLL; + } +| '-' LCONST + { + $$ = -$2 & 0xffffffffLL; + } +| LCONST '-' LCONST + { + $$ = ($1 & 0xffffffffLL) + + (($3 & 0xffffLL) << 32); + } +| '-' LCONST '-' LCONST + { + $$ = (-$2 & 0xffffffffLL) + + (($4 & 0xffffLL) << 32); + } + expr: con | expr '+' expr diff -r d8d00747375b sys/src/cmd/6a/lex.c --- a/sys/src/cmd/6a/lex.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/6a/lex.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,20 +1,76 @@ +// Inferno utils/6a/lex.c +// http://code.google.com/p/inferno-os/source/browse/utils/6a/lex.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. + #define EXTERN +#include +#include #include "a.h" #include "y.tab.h" -#include + +enum +{ + Plan9 = 1<<0, + Unix = 1<<1, + Windows = 1<<2, +}; + +int +systemtype(int sys) +{ +#ifdef _WIN32 + return sys&Windows; +#else + return sys&Plan9; +#endif +} + +int +pathchar(void) +{ + return '/'; +} void main(int argc, char *argv[]) { char *p; - int nout, nproc, status, i, c; + int c; thechar = '6'; thestring = "amd64"; + + ensuresymb(NSYMB); memset(debug, 0, sizeof(debug)); cinit(); outfile = 0; - include[ninclude++] = "."; + setinclude("."); ARGBEGIN { default: c = ARGC(); @@ -28,8 +84,12 @@ case 'D': p = ARGF(); - if(p) + if(p) { + if (nDlist%8 == 0) + Dlist = allocn(Dlist, nDlist*sizeof(char *), + 8*sizeof(char *)); Dlist[nDlist++] = p; + } break; case 'I': @@ -41,49 +101,10 @@ print("usage: %ca [-options] file.s\n", thechar); errorexit(); } - if(argc > 1 && systemtype(Windows)){ - print("can't assemble multiple files on windows\n"); + if(argc > 1){ + print("can't assemble multiple files\n"); errorexit(); } - if(argc > 1 && !systemtype(Windows)) { - nproc = 1; - if(p = getenv("NPROC")) - nproc = atol(p); /* */ - c = 0; - nout = 0; - for(;;) { - while(nout < nproc && argc > 0) { - i = myfork(); - if(i < 0) { - i = mywait(&status); - if(i < 0) - errorexit(); - if(status) - c++; - nout--; - continue; - } - if(i == 0) { - print("%s:\n", *argv); - if(assemble(*argv)) - errorexit(); - exits(0); - } - nout++; - argc--; - argv++; - } - i = mywait(&status); - if(i < 0) { - if(c) - errorexit(); - exits(0); - } - if(status) - c++; - nout--; - } - } if(assemble(argv[0])) errorexit(); exits(0); @@ -92,9 +113,10 @@ int assemble(char *file) { - char ofile[100], incfile[20], *p; + char *ofile, incfile[20], *p; int i, of; + ofile = alloc(strlen(file)+3); // +3 for .x\0 (x=thechar) strcpy(ofile, file); p = utfrrune(ofile, pathchar()); if(p) { @@ -126,7 +148,7 @@ } } - of = mycreat(outfile, 0664); + of = create(outfile, OWRITE, 0664); if(of < 0) { yyerror("%ca: cannot create %s", thechar, outfile); errorexit(); @@ -135,6 +157,9 @@ pass = 1; pinit(file); + + Bprint(&obuf, "go object %s %s %s\n", getgoos(), thestring, getgoversion()); + for(i=0; i>8); - Bputc(&obuf, lineno); - Bputc(&obuf, lineno>>8); - Bputc(&obuf, lineno>>16); - Bputc(&obuf, lineno>>24); + Bputc(&obuf, stmtline); + Bputc(&obuf, stmtline>>8); + Bputc(&obuf, stmtline>>16); + Bputc(&obuf, stmtline>>24); zaddr(&g2->from, sf); zaddr(&g2->to, st); out: - if(a != AGLOBL && a != ADATA && a != AMODE) + if(a != AGLOBL && a != ADATA) pc++; } @@ -1227,17 +1264,13 @@ for(h = hist; h != H; h = h->link) { p = h->name; op = 0; - /* on windows skip drive specifier in pathname */ if(systemtype(Windows) && p && p[1] == ':'){ - p += 2; - c = *p; - } - if(p && p[0] != c && h->offset == 0 && pathname){ - /* on windows skip drive specifier in pathname */ + c = p[2]; + } else if(p && p[0] != c && h->offset == 0 && pathname){ if(systemtype(Windows) && pathname[1] == ':') { op = p; - p = pathname+2; - c = *p; + p = pathname; + c = p[2]; } else if(pathname[0] == c){ op = p; p = pathname; @@ -1284,6 +1317,19 @@ } } +void +pragbldicks(void) +{ + while(getnsc() != '\n') + ; +} + +void +praghjdicks(void) +{ + while(getnsc() != '\n') + ; +} + #include "../cc/lexbody" #include "../cc/macbody" -#include "../cc/compat" diff -r d8d00747375b sys/src/cmd/6a/mkfile --- a/sys/src/cmd/6a/mkfile Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/6a/mkfile Mon Nov 14 17:35:25 2011 +0100 @@ -6,7 +6,7 @@ lex.$O\ HFILES=\ - ../6c/6.out.h\ + ../6l/6.out.h\ y.tab.h\ a.h\ @@ -23,4 +23,4 @@ < /sys/src/cmd/mkone YFLAGS=-D1 -d -lex.$O: ../cc/macbody ../cc/lexbody ../cc/compat +lex.$O: ../cc/macbody ../cc/lexbody diff -r d8d00747375b sys/src/cmd/6c/6.out.h --- a/sys/src/cmd/6c/6.out.h Thu Sep 29 03:00:00 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,820 +0,0 @@ -#define NSYM 50 -#define NSNAME 8 -#define NOPROF (1<<0) -#define DUPOK (1<<1) - -/* - * amd64 - */ - -enum as -{ - AXXX, - AAAA, - AAAD, - AAAM, - AAAS, - AADCB, - AADCL, - AADCW, - AADDB, - AADDL, - AADDW, - AADJSP, - AANDB, - AANDL, - AANDW, - AARPL, - ABOUNDL, - ABOUNDW, - ABSFL, - ABSFW, - ABSRL, - ABSRW, - ABTL, - ABTW, - ABTCL, - ABTCW, - ABTRL, - ABTRW, - ABTSL, - ABTSW, - ABYTE, - ACALL, - ACLC, - ACLD, - ACLI, - ACLTS, - ACMC, - ACMPB, - ACMPL, - ACMPW, - ACMPSB, - ACMPSL, - ACMPSW, - ADAA, - ADAS, - ADATA, - ADECB, - ADECL, - ADECQ, - ADECW, - ADIVB, - ADIVL, - ADIVW, - AENTER, - AGLOBL, - AGOK, - AHISTORY, - AHLT, - AIDIVB, - AIDIVL, - AIDIVW, - AIMULB, - AIMULL, - AIMULW, - AINB, - AINL, - AINW, - AINCB, - AINCL, - AINCQ, - AINCW, - AINSB, - AINSL, - AINSW, - AINT, - AINTO, - AIRETL, - AIRETW, - AJCC, - AJCS, - AJCXZ, - AJEQ, - AJGE, - AJGT, - AJHI, - AJLE, - AJLS, - AJLT, - AJMI, - AJMP, - AJNE, - AJOC, - AJOS, - AJPC, - AJPL, - AJPS, - ALAHF, - ALARL, - ALARW, - ALEAL, - ALEAW, - ALEAVEL, - ALEAVEW, - ALOCK, - ALODSB, - ALODSL, - ALODSW, - ALONG, - ALOOP, - ALOOPEQ, - ALOOPNE, - ALSLL, - ALSLW, - AMOVB, - AMOVL, - AMOVW, - AMOVBLSX, - AMOVBLZX, - AMOVBQSX, - AMOVBQZX, - AMOVBWSX, - AMOVBWZX, - AMOVWLSX, - AMOVWLZX, - AMOVWQSX, - AMOVWQZX, - AMOVSB, - AMOVSL, - AMOVSW, - AMULB, - AMULL, - AMULW, - ANAME, - ANEGB, - ANEGL, - ANEGW, - ANOP, - ANOTB, - ANOTL, - ANOTW, - AORB, - AORL, - AORW, - AOUTB, - AOUTL, - AOUTW, - AOUTSB, - AOUTSL, - AOUTSW, - APOPAL, - APOPAW, - APOPFL, - APOPFW, - APOPL, - APOPW, - APUSHAL, - APUSHAW, - APUSHFL, - APUSHFW, - APUSHL, - APUSHW, - ARCLB, - ARCLL, - ARCLW, - ARCRB, - ARCRL, - ARCRW, - AREP, - AREPN, - ARET, - AROLB, - AROLL, - AROLW, - ARORB, - ARORL, - ARORW, - ASAHF, - ASALB, - ASALL, - ASALW, - ASARB, - ASARL, - ASARW, - ASBBB, - ASBBL, - ASBBW, - ASCASB, - ASCASL, - ASCASW, - ASETCC, - ASETCS, - ASETEQ, - ASETGE, - ASETGT, - ASETHI, - ASETLE, - ASETLS, - ASETLT, - ASETMI, - ASETNE, - ASETOC, - ASETOS, - ASETPC, - ASETPL, - ASETPS, - ACDQ, - ACWD, - ASHLB, - ASHLL, - ASHLW, - ASHRB, - ASHRL, - ASHRW, - ASTC, - ASTD, - ASTI, - ASTOSB, - ASTOSL, - ASTOSW, - ASUBB, - ASUBL, - ASUBW, - ASYSCALL, - ATESTB, - ATESTL, - ATESTW, - ATEXT, - AVERR, - AVERW, - AWAIT, - AWORD, - AXCHGB, - AXCHGL, - AXCHGW, - AXLAT, - AXORB, - AXORL, - AXORW, - - AFMOVB, - AFMOVBP, - AFMOVD, - AFMOVDP, - AFMOVF, - AFMOVFP, - AFMOVL, - AFMOVLP, - AFMOVV, - AFMOVVP, - AFMOVW, - AFMOVWP, - AFMOVX, - AFMOVXP, - - AFCOMB, - AFCOMBP, - AFCOMD, - AFCOMDP, - AFCOMDPP, - AFCOMF, - AFCOMFP, - AFCOML, - AFCOMLP, - AFCOMW, - AFCOMWP, - AFUCOM, - AFUCOMP, - AFUCOMPP, - - AFADDDP, - AFADDW, - AFADDL, - AFADDF, - AFADDD, - - AFMULDP, - AFMULW, - AFMULL, - AFMULF, - AFMULD, - - AFSUBDP, - AFSUBW, - AFSUBL, - AFSUBF, - AFSUBD, - - AFSUBRDP, - AFSUBRW, - AFSUBRL, - AFSUBRF, - AFSUBRD, - - AFDIVDP, - AFDIVW, - AFDIVL, - AFDIVF, - AFDIVD, - - AFDIVRDP, - AFDIVRW, - AFDIVRL, - AFDIVRF, - AFDIVRD, - - AFXCHD, - AFFREE, - - AFLDCW, - AFLDENV, - AFRSTOR, - AFSAVE, - AFSTCW, - AFSTENV, - AFSTSW, - - AF2XM1, - AFABS, - AFCHS, - AFCLEX, - AFCOS, - AFDECSTP, - AFINCSTP, - AFINIT, - AFLD1, - AFLDL2E, - AFLDL2T, - AFLDLG2, - AFLDLN2, - AFLDPI, - AFLDZ, - AFNOP, - AFPATAN, - AFPREM, - AFPREM1, - AFPTAN, - AFRNDINT, - AFSCALE, - AFSIN, - AFSINCOS, - AFSQRT, - AFTST, - AFXAM, - AFXTRACT, - AFYL2X, - AFYL2XP1, - - AEND, - - ADYNT, - AINIT, - - ASIGNAME, - - /* extra 32-bit operations */ - ACMPXCHGB, - ACMPXCHGL, - ACMPXCHGW, - ACMPXCHG8B, - ACPUID, - AINVD, - AINVLPG, - ALFENCE, - AMFENCE, - AMOVNTIL, - ARDMSR, - ARDPMC, - ARDTSC, - ARSM, - ASFENCE, - ASYSRET, - AWBINVD, - AWRMSR, - AXADDB, - AXADDL, - AXADDW, - - /* conditional move */ - ACMOVLCC, - ACMOVLCS, - ACMOVLEQ, - ACMOVLGE, - ACMOVLGT, - ACMOVLHI, - ACMOVLLE, - ACMOVLLS, - ACMOVLLT, - ACMOVLMI, - ACMOVLNE, - ACMOVLOC, - ACMOVLOS, - ACMOVLPC, - ACMOVLPL, - ACMOVLPS, - ACMOVQCC, - ACMOVQCS, - ACMOVQEQ, - ACMOVQGE, - ACMOVQGT, - ACMOVQHI, - ACMOVQLE, - ACMOVQLS, - ACMOVQLT, - ACMOVQMI, - ACMOVQNE, - ACMOVQOC, - ACMOVQOS, - ACMOVQPC, - ACMOVQPL, - ACMOVQPS, - ACMOVWCC, - ACMOVWCS, - ACMOVWEQ, - ACMOVWGE, - ACMOVWGT, - ACMOVWHI, - ACMOVWLE, - ACMOVWLS, - ACMOVWLT, - ACMOVWMI, - ACMOVWNE, - ACMOVWOC, - ACMOVWOS, - ACMOVWPC, - ACMOVWPL, - ACMOVWPS, - - /* 64-bit */ - AADCQ, - AADDQ, - AANDQ, - ABSFQ, - ABSRQ, - ABTCQ, - ABTQ, - ABTRQ, - ABTSQ, - ACMPQ, - ACMPSQ, - ACMPXCHGQ, - ACQO, - ADIVQ, - AIDIVQ, - AIMULQ, - AIRETQ, - ALEAQ, - ALEAVEQ, - ALODSQ, - AMOVQ, - AMOVLQSX, - AMOVLQZX, - AMOVNTIQ, - AMOVSQ, - AMULQ, - ANEGQ, - ANOTQ, - AORQ, - APOPFQ, - APOPQ, - APUSHFQ, - APUSHQ, - ARCLQ, - ARCRQ, - AROLQ, - ARORQ, - AQUAD, - ASALQ, - ASARQ, - ASBBQ, - ASCASQ, - ASHLQ, - ASHRQ, - ASTOSQ, - ASUBQ, - ATESTQ, - AXADDQ, - AXCHGQ, - AXORQ, - - /* media */ - AADDPD, - AADDPS, - AADDSD, - AADDSS, - AANDNPD, - AANDNPS, - AANDPD, - AANDPS, - ACMPPD, - ACMPPS, - ACMPSD, - ACMPSS, - ACOMISD, - ACOMISS, - ACVTPD2PL, - ACVTPD2PS, - ACVTPL2PD, - ACVTPL2PS, - ACVTPS2PD, - ACVTPS2PL, - ACVTSD2SL, - ACVTSD2SQ, - ACVTSD2SS, - ACVTSL2SD, - ACVTSL2SS, - ACVTSQ2SD, - ACVTSQ2SS, - ACVTSS2SD, - ACVTSS2SL, - ACVTSS2SQ, - ACVTTPD2PL, - ACVTTPS2PL, - ACVTTSD2SL, - ACVTTSD2SQ, - ACVTTSS2SL, - ACVTTSS2SQ, - ADIVPD, - ADIVPS, - ADIVSD, - ADIVSS, - AEMMS, - AFXRSTOR, - AFXRSTOR64, - AFXSAVE, - AFXSAVE64, - ALDMXCSR, - AMASKMOVOU, - AMASKMOVQ, - AMAXPD, - AMAXPS, - AMAXSD, - AMAXSS, - AMINPD, - AMINPS, - AMINSD, - AMINSS, - AMOVAPD, - AMOVAPS, - AMOVOU, - AMOVHLPS, - AMOVHPD, - AMOVHPS, - AMOVLHPS, - AMOVLPD, - AMOVLPS, - AMOVMSKPD, - AMOVMSKPS, - AMOVNTO, - AMOVNTPD, - AMOVNTPS, - AMOVNTQ, - AMOVO, - AMOVQOZX, - AMOVSD, - AMOVSS, - AMOVUPD, - AMOVUPS, - AMULPD, - AMULPS, - AMULSD, - AMULSS, - AORPD, - AORPS, - APACKSSLW, - APACKSSWB, - APACKUSWB, - APADDB, - APADDL, - APADDQ, - APADDSB, - APADDSW, - APADDUSB, - APADDUSW, - APADDW, - APANDB, - APANDL, - APANDSB, - APANDSW, - APANDUSB, - APANDUSW, - APANDW, - APAND, - APANDN, - APAVGB, - APAVGW, - APCMPEQB, - APCMPEQL, - APCMPEQW, - APCMPGTB, - APCMPGTL, - APCMPGTW, - APEXTRW, - APFACC, - APFADD, - APFCMPEQ, - APFCMPGE, - APFCMPGT, - APFMAX, - APFMIN, - APFMUL, - APFNACC, - APFPNACC, - APFRCP, - APFRCPIT1, - APFRCPI2T, - APFRSQIT1, - APFRSQRT, - APFSUB, - APFSUBR, - APINSRW, - APMADDWL, - APMAXSW, - APMAXUB, - APMINSW, - APMINUB, - APMOVMSKB, - APMULHRW, - APMULHUW, - APMULHW, - APMULLW, - APMULULQ, - APOR, - APSADBW, - APSHUFHW, - APSHUFL, - APSHUFLW, - APSHUFW, - APSLLO, - APSLLL, - APSLLQ, - APSLLW, - APSRAL, - APSRAW, - APSRLO, - APSRLL, - APSRLQ, - APSRLW, - APSUBB, - APSUBL, - APSUBQ, - APSUBSB, - APSUBSW, - APSUBUSB, - APSUBUSW, - APSUBW, - APSWAPL, - APUNPCKHBW, - APUNPCKHLQ, - APUNPCKHQDQ, - APUNPCKHWL, - APUNPCKLBW, - APUNPCKLLQ, - APUNPCKLQDQ, - APUNPCKLWL, - APXOR, - ARCPPS, - ARCPSS, - ARSQRTPS, - ARSQRTSS, - ASHUFPD, - ASHUFPS, - ASQRTPD, - ASQRTPS, - ASQRTSD, - ASQRTSS, - ASTMXCSR, - ASUBPD, - ASUBPS, - ASUBSD, - ASUBSS, - AUCOMISD, - AUCOMISS, - AUNPCKHPD, - AUNPCKHPS, - AUNPCKLPD, - AUNPCKLPS, - AXORPD, - AXORPS, - - APF2IW, - APF2IL, - API2FW, - API2FL, - ARETFW, - ARETFL, - ARETFQ, - ASWAPGS, - - AMODE, - - ALAST -}; - -enum -{ - - D_AL = 0, - D_CL, - D_DL, - D_BL, - D_SPB, - D_BPB, - D_SIB, - D_DIB, - D_R8B, - D_R9B, - D_R10B, - D_R11B, - D_R12B, - D_R13B, - D_R14B, - D_R15B, - - D_AX = 16, - D_CX, - D_DX, - D_BX, - D_SP, - D_BP, - D_SI, - D_DI, - D_R8, - D_R9, - D_R10, - D_R11, - D_R12, - D_R13, - D_R14, - D_R15, - - D_AH = 32, - D_CH, - D_DH, - D_BH, - - D_F0 = 36, - - D_M0 = 44, - - D_X0 = 52, - - D_CS = 68, - D_SS, - D_DS, - D_ES, - D_FS, - D_GS, - - D_GDTR, /* global descriptor table register */ - D_IDTR, /* interrupt descriptor table register */ - D_LDTR, /* local descriptor table register */ - D_MSW, /* machine status word */ - D_TASK, /* task register */ - - D_CR = 79, - D_DR = 95, - D_TR = 103, - - D_NONE = 111, - - D_BRANCH = 112, - D_EXTERN = 113, - D_STATIC = 114, - D_AUTO = 115, - D_PARAM = 116, - D_CONST = 117, - D_FCONST = 118, - D_SCONST = 119, - D_ADDR = 120, - - D_FILE, - D_FILE1, - - D_INDIR, /* additive */ - - T_TYPE = 1<<0, - T_INDEX = 1<<1, - T_OFFSET = 1<<2, - T_FCONST = 1<<3, - T_SYM = 1<<4, - T_SCONST = 1<<5, - T_64 = 1<<6, - - REGARG = D_BP, /* MIGHT CHANGE */ - REGRET = D_AX, - FREGRET = D_X0, - REGSP = D_SP, - REGTMP = D_DI, - REGEXT = D_R15, /* compiler allocates external registers R15 down */ - FREGMIN = D_X0+5, /* first register variable */ - FREGEXT = D_X0+7 /* first external register */ -}; - -/* - * this is the ranlib header - */ -#define SYMDEF "__.SYMDEF" - -/* - * this is the simulated IEEE floating point - */ -typedef struct ieee Ieee; -struct ieee -{ - long l; /* contains ls-man 0xffffffff */ - long h; /* contains sign 0x80000000 - exp 0x7ff00000 - ms-man 0x000fffff */ -}; diff -r d8d00747375b sys/src/cmd/6c/cgen.c --- a/sys/src/cmd/6c/cgen.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/6c/cgen.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,17 +1,44 @@ +// Inferno utils/5c/cgen.c +// http://code.google.com/p/inferno-os/source/browse/utils/5c/cgen.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 "gc.h" -/* ,x/^(print|prtree)\(/i/\/\/ */ -int castup(Type*, Type*); - void -cgen(Node *n, Node *nn) +_cgen(Node *n, Node *nn, int inrel) { - Node *l, *r, *t; + Node *l, *r; Prog *p1; Node nod, nod1, nod2, nod3, nod4; - int o, hardleft; - long v, curs; - vlong c; + int o, t; + int32 v, curs; if(debug['g']) { prtree(nn, "cgen lhs"); @@ -19,7 +46,7 @@ } if(n == Z || n->type == T) return; - if(typesu[n->type->etype]) { + if(typesuv[n->type->etype]) { sugen(n, nn, n->type->width); return; } @@ -43,23 +70,20 @@ } curs = cursafe; + if(n->complex >= FNX) if(l->complex >= FNX) if(r != Z && r->complex >= FNX) switch(o) { default: - if(cond(o) && typesu[l->type->etype]) - break; - regret(&nod, r); cgen(r, &nod); regsalloc(&nod1, r); - gmove(&nod, &nod1); + gopcode(OAS, &nod, Z, &nod1); regfree(&nod); nod = *n; nod.right = &nod1; - cgen(&nod, nn); return; @@ -72,30 +96,16 @@ break; } - hardleft = l->addable < INDEXED || l->complex >= FNX; switch(o) { default: diag(n, "unknown op in cgen: %O", o); break; - case ONEG: - case OCOM: - if(nn == Z) { - nullwarn(l, Z); - break; - } - regalloc(&nod, l, nn); - cgen(l, &nod); - gopcode(o, n->type, Z, &nod); - gmove(&nod, nn); - regfree(&nod); - break; - case OAS: if(l->op == OBIT) goto bitas; - if(!hardleft) { - if(nn != Z || r->addable < INDEXED || hardconst(r)) { + if(l->addable >= INDEXED && l->complex < FNX) { + if(nn != Z || r->addable < INDEXED) { if(r->complex >= FNX && nn == Z) regret(&nod, r); else @@ -110,12 +120,8 @@ break; } if(l->complex >= r->complex) { - if(l->op == OINDEX && immconst(r)) { - gmove(r, l); - break; - } reglcgen(&nod1, l, Z); - if(r->addable >= INDEXED && !hardconst(r)) { + if(r->addable >= INDEXED) { gmove(r, &nod1); if(nn != Z) gmove(r, nn); @@ -145,7 +151,7 @@ reglcgen(&nod1, n, Z); } regalloc(&nod2, n, Z); - gmove(&nod1, &nod2); + gopcode(OAS, &nod1, Z, &nod2); bitstore(l, &nod, &nod1, &nod2, nn); break; @@ -155,312 +161,93 @@ break; } bitload(n, &nod, Z, Z, nn); - gmove(&nod, nn); + gopcode(OAS, &nod, Z, nn); regfree(&nod); break; + case ODIV: + case OMOD: + if(nn != Z) + if((t = vlog(r)) >= 0) { + /* signed div/mod by constant power of 2 */ + cgen(l, nn); + gopcode(OGE, nodconst(0), nn, Z); + p1 = p; + if(o == ODIV) { + gopcode(OADD, nodconst((1<op == OCONST) + if(!typefd[n->type->etype]) { + cgen(r, nn); + gopcode(o, Z, l, nn); + break; + } + case OADD: + case OAND: + case OOR: + case OXOR: case OLSHR: case OASHL: case OASHR: + /* + * immediate operands + */ + if(nn != Z) + if(r->op == OCONST) + if(!typefd[n->type->etype]) { + cgen(l, nn); + if(r->vconst == 0) + if(o != OAND) + break; + if(nn != Z) + gopcode(o, r, Z, nn); + break; + } + + case OLMUL: + case OLDIV: + case OLMOD: + case OMUL: + muldiv: if(nn == Z) { nullwarn(l, r); break; } - if(r->op == OCONST) { - if(r->vconst == 0) { - cgen(l, nn); + if(o == OMUL || o == OLMUL) { + if(mulcon(n, nn)) break; - } - regalloc(&nod, l, nn); - cgen(l, &nod); - if(o == OASHL && r->vconst == 1) - gopcode(OADD, n->type, &nod, &nod); - else - gopcode(o, n->type, r, &nod); - gmove(&nod, nn); - regfree(&nod); - break; - } - - /* - * get nod to be D_CX - */ - if(nodreg(&nod, nn, D_CX)) { - regsalloc(&nod1, n); - gmove(&nod, &nod1); - cgen(n, &nod); /* probably a bug */ - gmove(&nod, nn); - gmove(&nod1, &nod); - break; - } - reg[D_CX]++; - if(nn->op == OREGISTER && nn->reg == D_CX) - regalloc(&nod1, l, Z); - else - regalloc(&nod1, l, nn); - if(r->complex >= l->complex) { - cgen(r, &nod); - cgen(l, &nod1); - } else { - cgen(l, &nod1); - cgen(r, &nod); - } - gopcode(o, n->type, &nod, &nod1); - gmove(&nod1, nn); - regfree(&nod); - regfree(&nod1); - break; - - case OADD: - case OSUB: - case OOR: - case OXOR: - case OAND: - if(nn == Z) { - nullwarn(l, r); - break; - } - if(typefd[n->type->etype]) - goto fop; - if(r->op == OCONST) { - if(r->vconst == 0 && o != OAND) { - cgen(l, nn); - break; - } - } - if(n->op == OADD && l->op == OASHL && l->right->op == OCONST - && (r->op != OCONST || r->vconst < -128 || r->vconst > 127)) { - c = l->right->vconst; - if(c > 0 && c <= 3) { - if(l->left->complex >= r->complex) { - regalloc(&nod, l->left, nn); - cgen(l->left, &nod); - if(r->addable < INDEXED) { - regalloc(&nod1, r, Z); - cgen(r, &nod1); - genmuladd(&nod, &nod, 1 << c, &nod1); - regfree(&nod1); - } - else - genmuladd(&nod, &nod, 1 << c, r); - } - else { - regalloc(&nod, r, nn); - cgen(r, &nod); - regalloc(&nod1, l->left, Z); - cgen(l->left, &nod1); - genmuladd(&nod, &nod1, 1 << c, &nod); - regfree(&nod1); - } - gmove(&nod, nn); - regfree(&nod); - break; - } - } - if(r->addable >= INDEXED && !hardconst(r)) { - regalloc(&nod, l, nn); - cgen(l, &nod); - gopcode(o, n->type, r, &nod); - gmove(&nod, nn); - regfree(&nod); - break; } if(l->complex >= r->complex) { regalloc(&nod, l, nn); cgen(l, &nod); regalloc(&nod1, r, Z); cgen(r, &nod1); - gopcode(o, n->type, &nod1, &nod); + gopcode(o, &nod1, Z, &nod); } else { - regalloc(&nod1, r, nn); - cgen(r, &nod1); - regalloc(&nod, l, Z); - cgen(l, &nod); - gopcode(o, n->type, &nod1, &nod); + regalloc(&nod, r, nn); + cgen(r, &nod); + regalloc(&nod1, l, Z); + cgen(l, &nod1); + gopcode(o, &nod, &nod1, &nod); } - gmove(&nod, nn); - regfree(&nod); - regfree(&nod1); - break; - - case OLMOD: - case OMOD: - case OLMUL: - case OLDIV: - case OMUL: - case ODIV: - if(nn == Z) { - nullwarn(l, r); - break; - } - if(typefd[n->type->etype]) - goto fop; - if(r->op == OCONST && typechl[n->type->etype]) { /* TO DO */ - SET(v); - switch(o) { - case ODIV: - case OMOD: - c = r->vconst; - if(c < 0) - c = -c; - v = log2(c); - if(v < 0) - break; - /* fall thru */ - case OMUL: - case OLMUL: - regalloc(&nod, l, nn); - cgen(l, &nod); - switch(o) { - case OMUL: - case OLMUL: - mulgen(n->type, r, &nod); - break; - case ODIV: - sdiv2(r->vconst, v, l, &nod); - break; - case OMOD: - smod2(r->vconst, v, l, &nod); - break; - } - gmove(&nod, nn); - regfree(&nod); - goto done; - case OLDIV: - c = r->vconst; - if((c & 0x80000000) == 0) - break; - regalloc(&nod1, l, Z); - cgen(l, &nod1); - regalloc(&nod, l, nn); - zeroregm(&nod); - gins(ACMPL, &nod1, nodconst(c)); - gins(ASBBL, nodconst(-1), &nod); - regfree(&nod1); - gmove(&nod, nn); - regfree(&nod); - goto done; - } - } - - if(o == OMUL) { - if(l->addable >= INDEXED) { - t = l; - l = r; - r = t; - } - /* should favour AX */ - regalloc(&nod, l, nn); - cgen(l, &nod); - if(r->addable < INDEXED || hardconst(r)) { - regalloc(&nod1, r, Z); - cgen(r, &nod1); - gopcode(OMUL, n->type, &nod1, &nod); - regfree(&nod1); - }else - gopcode(OMUL, n->type, r, &nod); /* addressible */ - gmove(&nod, nn); - regfree(&nod); - break; - } - - /* - * get nod to be D_AX - * get nod1 to be D_DX - */ - if(nodreg(&nod, nn, D_AX)) { - regsalloc(&nod2, n); - gmove(&nod, &nod2); - v = reg[D_AX]; - reg[D_AX] = 0; - - if(isreg(l, D_AX)) { - nod3 = *n; - nod3.left = &nod2; - cgen(&nod3, nn); - } else - if(isreg(r, D_AX)) { - nod3 = *n; - nod3.right = &nod2; - cgen(&nod3, nn); - } else - cgen(n, nn); - - gmove(&nod2, &nod); - reg[D_AX] = v; - break; - } - if(nodreg(&nod1, nn, D_DX)) { - regsalloc(&nod2, n); - gmove(&nod1, &nod2); - v = reg[D_DX]; - reg[D_DX] = 0; - - if(isreg(l, D_DX)) { - nod3 = *n; - nod3.left = &nod2; - cgen(&nod3, nn); - } else - if(isreg(r, D_DX)) { - nod3 = *n; - nod3.right = &nod2; - cgen(&nod3, nn); - } else - cgen(n, nn); - - gmove(&nod2, &nod1); - reg[D_DX] = v; - break; - } - reg[D_AX]++; - - if(r->op == OCONST && (o == ODIV || o == OLDIV) && immconst(r) && typechl[r->type->etype]) { - reg[D_DX]++; - if(l->addable < INDEXED) { - regalloc(&nod2, l, Z); - cgen(l, &nod2); - l = &nod2; - } - if(o == ODIV) - sdivgen(l, r, &nod, &nod1); - else - udivgen(l, r, &nod, &nod1); - gmove(&nod1, nn); - if(l == &nod2) - regfree(l); - goto freeaxdx; - } - - if(l->complex >= r->complex) { - cgen(l, &nod); - reg[D_DX]++; - if(o == ODIV || o == OMOD) - gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z); - if(o == OLDIV || o == OLMOD) - zeroregm(&nod1); - if(r->addable < INDEXED || r->op == OCONST) { - regalloc(&nod3, r, Z); - cgen(r, &nod3); - gopcode(o, n->type, &nod3, Z); - regfree(&nod3); - } else - gopcode(o, n->type, r, Z); - } else { - regsalloc(&nod3, r); - cgen(r, &nod3); - cgen(l, &nod); - reg[D_DX]++; - if(o == ODIV || o == OMOD) - gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z); - if(o == OLDIV || o == OLMOD) - zeroregm(&nod1); - gopcode(o, n->type, &nod3, Z); - } - if(o == OMOD || o == OLMOD) - gmove(&nod1, nn); - else - gmove(&nod, nn); - freeaxdx: + gopcode(OAS, &nod, Z, nn); regfree(&nod); regfree(&nod1); break; @@ -468,130 +255,30 @@ case OASLSHR: case OASASHL: case OASASHR: - if(r->op == OCONST) - goto asand; - if(l->op == OBIT) - goto asbitop; - if(typefd[n->type->etype]) - goto asand; /* can this happen? */ - - /* - * get nod to be D_CX - */ - if(nodreg(&nod, nn, D_CX)) { - regsalloc(&nod1, n); - gmove(&nod, &nod1); - cgen(n, &nod); - if(nn != Z) - gmove(&nod, nn); - gmove(&nod1, &nod); - break; - } - reg[D_CX]++; - - if(r->complex >= l->complex) { - cgen(r, &nod); - if(hardleft) - reglcgen(&nod1, l, Z); - else - nod1 = *l; - } else { - if(hardleft) - reglcgen(&nod1, l, Z); - else - nod1 = *l; - cgen(r, &nod); - } - - gopcode(o, l->type, &nod, &nod1); - regfree(&nod); - if(nn != Z) - gmove(&nod1, nn); - if(hardleft) - regfree(&nod1); - break; - case OASAND: case OASADD: case OASSUB: case OASXOR: case OASOR: - asand: if(l->op == OBIT) goto asbitop; - if(typefd[l->type->etype] || typefd[r->type->etype]) - goto asfop; - if(l->complex >= r->complex) { - if(hardleft) - reglcgen(&nod, l, Z); + if(r->op == OCONST) + if(!typefd[r->type->etype]) + if(!typefd[n->type->etype]) { + if(l->addable < INDEXED) + reglcgen(&nod2, l, Z); else - nod = *l; - if(!immconst(r)) { - regalloc(&nod1, r, nn); - cgen(r, &nod1); - gopcode(o, l->type, &nod1, &nod); - regfree(&nod1); - } else - gopcode(o, l->type, r, &nod); - } else { - regalloc(&nod1, r, nn); - cgen(r, &nod1); - if(hardleft) - reglcgen(&nod, l, Z); - else - nod = *l; - gopcode(o, l->type, &nod1, &nod); - regfree(&nod1); + nod2 = *l; + regalloc(&nod, r, nn); + gopcode(OAS, &nod2, Z, &nod); + gopcode(o, r, Z, &nod); + gopcode(OAS, &nod, Z, &nod2); + + regfree(&nod); + if(l->addable < INDEXED) + regfree(&nod2); + break; } - if(nn != Z) - gmove(&nod, nn); - if(hardleft) - regfree(&nod); - break; - - asfop: - if(l->complex >= r->complex) { - if(hardleft) - reglcgen(&nod, l, Z); - else - nod = *l; - if(r->addable < INDEXED){ - regalloc(&nod1, r, nn); - cgen(r, &nod1); - }else - nod1 = *r; - regalloc(&nod2, r, Z); - gmove(&nod, &nod2); - gopcode(o, r->type, &nod1, &nod2); - gmove(&nod2, &nod); - regfree(&nod2); - if(r->addable < INDEXED) - regfree(&nod1); - } else { - regalloc(&nod1, r, nn); - cgen(r, &nod1); - if(hardleft) - reglcgen(&nod, l, Z); - else - nod = *l; - if(o != OASMUL && o != OASADD) { - regalloc(&nod2, r, Z); - gmove(&nod, &nod2); - gopcode(o, r->type, &nod1, &nod2); - regfree(&nod1); - gmove(&nod2, &nod); - regfree(&nod2); - } else { - gopcode(o, r->type, &nod, &nod1); - gmove(&nod1, &nod); - regfree(&nod1); - } - } - if(nn != Z) - gmove(&nod, nn); - if(hardleft) - regfree(&nod); - break; case OASLMUL: case OASLDIV: @@ -601,237 +288,32 @@ case OASMOD: if(l->op == OBIT) goto asbitop; - if(typefd[n->type->etype] || typefd[r->type->etype]) - goto asfop; - if(r->op == OCONST && typechl[n->type->etype]) { - SET(v); - switch(o) { - case OASDIV: - case OASMOD: - c = r->vconst; - if(c < 0) - c = -c; - v = log2(c); - if(v < 0) - break; - /* fall thru */ - case OASMUL: - case OASLMUL: - if(hardleft) - reglcgen(&nod2, l, Z); - else - nod2 = *l; - regalloc(&nod, l, nn); - cgen(&nod2, &nod); - switch(o) { - case OASMUL: - case OASLMUL: - mulgen(n->type, r, &nod); - break; - case OASDIV: - sdiv2(r->vconst, v, l, &nod); - break; - case OASMOD: - smod2(r->vconst, v, l, &nod); - break; - } - havev: - gmove(&nod, &nod2); - if(nn != Z) - gmove(&nod, nn); - if(hardleft) - regfree(&nod2); - regfree(&nod); - goto done; - case OASLDIV: - c = r->vconst; - if((c & 0x80000000) == 0) - break; - if(hardleft) - reglcgen(&nod2, l, Z); - else - nod2 = *l; - regalloc(&nod1, l, nn); - cgen(&nod2, &nod1); - regalloc(&nod, l, nn); - zeroregm(&nod); - gins(ACMPL, &nod1, nodconst(c)); - gins(ASBBL, nodconst(-1), &nod); - regfree(&nod1); - goto havev; - } - } - - if(o == OASMUL) { - /* should favour AX */ - regalloc(&nod, l, nn); - if(r->complex >= FNX) { - regalloc(&nod1, r, Z); - cgen(r, &nod1); - r = &nod1; - } - if(hardleft) + if(l->complex >= r->complex) { + if(l->addable < INDEXED) reglcgen(&nod2, l, Z); else nod2 = *l; - cgen(&nod2, &nod); - if(r->addable < INDEXED || hardconst(r)) { - if(r->complex < FNX) { - regalloc(&nod1, r, Z); - cgen(r, &nod1); - } - gopcode(OASMUL, n->type, &nod1, &nod); - regfree(&nod1); - } - else - gopcode(OASMUL, n->type, r, &nod); - if(r == &nod1) - regfree(r); - gmove(&nod, &nod2); - if(nn != Z) - gmove(&nod, nn); - regfree(&nod); - if(hardleft) - regfree(&nod2); - break; - } - - /* - * get nod to be D_AX - * get nod1 to be D_DX - */ - if(nodreg(&nod, nn, D_AX)) { - regsalloc(&nod2, n); - gmove(&nod, &nod2); - v = reg[D_AX]; - reg[D_AX] = 0; - - if(isreg(l, D_AX)) { - nod3 = *n; - nod3.left = &nod2; - cgen(&nod3, nn); - } else - if(isreg(r, D_AX)) { - nod3 = *n; - nod3.right = &nod2; - cgen(&nod3, nn); - } else - cgen(n, nn); - - gmove(&nod2, &nod); - reg[D_AX] = v; - break; - } - if(nodreg(&nod1, nn, D_DX)) { - regsalloc(&nod2, n); - gmove(&nod1, &nod2); - v = reg[D_DX]; - reg[D_DX] = 0; - - if(isreg(l, D_DX)) { - nod3 = *n; - nod3.left = &nod2; - cgen(&nod3, nn); - } else - if(isreg(r, D_DX)) { - nod3 = *n; - nod3.right = &nod2; - cgen(&nod3, nn); - } else - cgen(n, nn); - - gmove(&nod2, &nod1); - reg[D_DX] = v; - break; - } - reg[D_AX]++; - reg[D_DX]++; - - if(l->complex >= r->complex) { - if(hardleft) + regalloc(&nod1, r, Z); + cgen(r, &nod1); + } else { + regalloc(&nod1, r, Z); + cgen(r, &nod1); + if(l->addable < INDEXED) reglcgen(&nod2, l, Z); else nod2 = *l; - cgen(&nod2, &nod); - if(r->op == OCONST && typechl[r->type->etype]) { - switch(o) { - case OASDIV: - sdivgen(&nod2, r, &nod, &nod1); - goto divdone; - case OASLDIV: - udivgen(&nod2, r, &nod, &nod1); - divdone: - gmove(&nod1, &nod2); - if(nn != Z) - gmove(&nod1, nn); - goto freelxaxdx; - } - } - if(o == OASDIV || o == OASMOD) - gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z); - if(o == OASLDIV || o == OASLMOD) - zeroregm(&nod1); - if(r->addable < INDEXED || r->op == OCONST || - !typeil[r->type->etype]) { - regalloc(&nod3, r, Z); - cgen(r, &nod3); - gopcode(o, l->type, &nod3, Z); - regfree(&nod3); - } else - gopcode(o, n->type, r, Z); - } else { - regalloc(&nod3, r, Z); - cgen(r, &nod3); - if(hardleft) - reglcgen(&nod2, l, Z); - else - nod2 = *l; - cgen(&nod2, &nod); - if(o == OASDIV || o == OASMOD) - gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z); - if(o == OASLDIV || o == OASLMOD) - zeroregm(&nod1); - gopcode(o, l->type, &nod3, Z); - regfree(&nod3); } - if(o == OASMOD || o == OASLMOD) { - gmove(&nod1, &nod2); - if(nn != Z) - gmove(&nod1, nn); - } else { - gmove(&nod, &nod2); - if(nn != Z) - gmove(&nod, nn); - } - freelxaxdx: - if(hardleft) - regfree(&nod2); + + regalloc(&nod, n, nn); + gmove(&nod2, &nod); + gopcode(o, &nod1, Z, &nod); + gmove(&nod, &nod2); + if(nn != Z) + gopcode(OAS, &nod, Z, nn); regfree(&nod); regfree(&nod1); - break; - - fop: - if(l->complex >= r->complex) { - regalloc(&nod, l, nn); - cgen(l, &nod); - if(r->addable < INDEXED) { - regalloc(&nod1, r, Z); - cgen(r, &nod1); - gopcode(o, n->type, &nod1, &nod); - regfree(&nod1); - } else - gopcode(o, n->type, r, &nod); - } else { - /* TO DO: could do better with r->addable >= INDEXED */ - regalloc(&nod1, r, Z); - cgen(r, &nod1); - regalloc(&nod, l, nn); - cgen(l, &nod); - gopcode(o, n->type, &nod1, &nod); - regfree(&nod1); - } - gmove(&nod, nn); - regfree(&nod); + if(l->addable < INDEXED) + regfree(&nod2); break; asbitop: @@ -846,20 +328,7 @@ bitload(l, &nod, &nod1, &nod2, &nod4); } gmove(&nod, &nod4); - - { /* TO DO: check floating point source */ - Node onod; - - /* incredible grot ... */ - onod = nod3; - onod.op = o; - onod.complex = 2; - onod.addable = 0; - onod.type = tfield; - onod.left = &nod4; - onod.right = &nod3; - cgen(&onod, Z); - } + gopcode(o, &nod3, Z, &nod4); regfree(&nod3); gmove(&nod4, &nod); regfree(&nod4); @@ -882,7 +351,7 @@ regret(&nod, l->left); cgen(l->left, &nod); regsalloc(&nod1, l->left); - gmove(&nod, &nod1); + gopcode(OAS, &nod, Z, &nod1); regfree(&nod); nod = *n; @@ -894,21 +363,21 @@ return; } - o = reg[REGARG]; + if(REGARG >= 0) + o = reg[REGARG]; gargs(r, &nod, &nod1); if(l->addable < INDEXED) { - reglcgen(&nod, l, nn); - nod.op = OREGISTER; - gopcode(OFUNC, n->type, Z, &nod); + reglcgen(&nod, l, Z); + gopcode(OFUNC, Z, Z, &nod); regfree(&nod); } else - gopcode(OFUNC, n->type, Z, l); - if(REGARG) + gopcode(OFUNC, Z, Z, l); + if(REGARG >= 0) if(o != reg[REGARG]) reg[REGARG]--; if(nn != Z) { regret(&nod, n); - gmove(&nod, nn); + gopcode(OAS, &nod, Z, nn); regfree(&nod); } break; @@ -922,7 +391,7 @@ r = l; while(r->op == OADD) r = r->right; - if(sconst(r)) { + if(sconst(r) && (v = r->vconst+nod.xoffset) > -4096 && v < 4096) { v = r->vconst; r->vconst = 0; cgen(l, &nod); @@ -931,7 +400,7 @@ } else cgen(l, &nod); regind(&nod, n); - gmove(&nod, nn); + gopcode(OAS, &nod, Z, nn); regfree(&nod); break; @@ -980,48 +449,37 @@ /* * convert from types l->n->nn */ - if(nocast(l->type, n->type) && nocast(n->type, nn->type)) { - /* both null, gen l->nn */ - cgen(l, nn); - break; - } - if(ewidth[n->type->etype] < ewidth[l->type->etype]){ - if(l->type->etype == TIND && typechlp[n->type->etype]) - warn(n, "conversion of pointer to shorter integer"); - }else if(0){ - if(nocast(n->type, nn->type) || castup(n->type, nn->type)){ - if(typefd[l->type->etype] != typefd[nn->type->etype]) - regalloc(&nod, l, nn); - else - regalloc(&nod, nn, nn); - cgen(l, &nod); - gmove(&nod, nn); - regfree(&nod); + if(nocast(l->type, n->type)) { + if(nocast(n->type, nn->type)) { + cgen(l, nn); break; } } regalloc(&nod, l, nn); cgen(l, &nod); regalloc(&nod1, n, &nod); - gmove(&nod, &nod1); - gmove(&nod1, nn); + if(inrel) + gmover(&nod, &nod1); + else + gopcode(OAS, &nod, Z, &nod1); + gopcode(OAS, &nod1, Z, nn); regfree(&nod1); regfree(&nod); break; case ODOT: sugen(l, nodrat, l->type->width); - if(nn == Z) - break; - warn(n, "non-interruptable temporary"); - nod = *nodrat; - if(!r || r->op != OCONST) { - diag(n, "DOT and no offset"); - break; + if(nn != Z) { + warn(n, "non-interruptable temporary"); + nod = *nodrat; + if(!r || r->op != OCONST) { + diag(n, "DOT and no offset"); + break; + } + nod.xoffset += (int32)r->vconst; + nod.type = n->type; + cgen(&nod, nn); } - nod.xoffset += (long)r->vconst; - nod.type = n->type; - cgen(&nod, nn); break; case OCOND: @@ -1047,25 +505,32 @@ if(nn == Z) goto pre; - if(hardleft) - reglcgen(&nod, l, Z); + if(l->addable < INDEXED) + reglcgen(&nod2, l, Z); else - nod = *l; + nod2 = *l; - gmove(&nod, nn); - if(typefd[n->type->etype]) { - regalloc(&nod1, l, Z); - gmove(&nod, &nod1); - if(v < 0) - gopcode(OSUB, n->type, nodfconst(-v), &nod1); - else - gopcode(OADD, n->type, nodfconst(v), &nod1); - gmove(&nod1, &nod); - regfree(&nod1); + regalloc(&nod, l, nn); + gopcode(OAS, &nod2, Z, &nod); + regalloc(&nod1, l, Z); + if(typefd[l->type->etype]) { + regalloc(&nod3, l, Z); + if(v < 0) { + gopcode(OAS, nodfconst(-v), Z, &nod3); + gopcode(OSUB, &nod3, &nod, &nod1); + } else { + gopcode(OAS, nodfconst(v), Z, &nod3); + gopcode(OADD, &nod3, &nod, &nod1); + } + regfree(&nod3); } else - gopcode(OADD, n->type, nodconst(v), &nod); - if(hardleft) - regfree(&nod); + gopcode(OADD, nodconst(v), &nod, &nod1); + gopcode(OAS, &nod1, Z, &nod2); + + regfree(&nod); + regfree(&nod1); + if(l->addable < INDEXED) + regfree(&nod2); break; case OPREINC: @@ -1079,56 +544,73 @@ goto bitinc; pre: - if(hardleft) - reglcgen(&nod, l, Z); + if(l->addable < INDEXED) + reglcgen(&nod2, l, Z); else - nod = *l; - if(typefd[n->type->etype]) { - regalloc(&nod1, l, Z); - gmove(&nod, &nod1); - if(v < 0) - gopcode(OSUB, n->type, nodfconst(-v), &nod1); - else - gopcode(OADD, n->type, nodfconst(v), &nod1); - gmove(&nod1, &nod); - regfree(&nod1); + nod2 = *l; + + regalloc(&nod, l, nn); + gopcode(OAS, &nod2, Z, &nod); + if(typefd[l->type->etype]) { + regalloc(&nod3, l, Z); + if(v < 0) { + gopcode(OAS, nodfconst(-v), Z, &nod3); + gopcode(OSUB, &nod3, Z, &nod); + } else { + gopcode(OAS, nodfconst(v), Z, &nod3); + gopcode(OADD, &nod3, Z, &nod); + } + regfree(&nod3); } else - gopcode(OADD, n->type, nodconst(v), &nod); - if(nn != Z) - gmove(&nod, nn); - if(hardleft) - regfree(&nod); + gopcode(OADD, nodconst(v), Z, &nod); + gopcode(OAS, &nod, Z, &nod2); + + regfree(&nod); + if(l->addable < INDEXED) + regfree(&nod2); break; bitinc: if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) { bitload(l, &nod, &nod1, &nod2, Z); - gmove(&nod, nn); - gopcode(OADD, tfield, nodconst(v), &nod); + gopcode(OAS, &nod, Z, nn); + gopcode(OADD, nodconst(v), Z, &nod); bitstore(l, &nod, &nod1, &nod2, Z); break; } bitload(l, &nod, &nod1, &nod2, nn); - gopcode(OADD, tfield, nodconst(v), &nod); + gopcode(OADD, nodconst(v), Z, &nod); bitstore(l, &nod, &nod1, &nod2, nn); break; } -done: cursafe = curs; + return; +} + +void +cgen(Node *n, Node *nn) +{ + _cgen(n, nn, 0); +} + +void +cgenrel(Node *n, Node *nn) +{ + _cgen(n, nn, 1); } void reglcgen(Node *t, Node *n, Node *nn) { Node *r; - long v; + int32 v; regialloc(t, n, nn); if(n->op == OIND) { r = n->left; while(r->op == OADD) r = r->right; - if(sconst(r)) { + if(sconst(r) && (v = r->vconst+t->xoffset) > -4096 && v < 4096) { v = r->vconst; r->vconst = 0; lcgen(n, t); @@ -1137,12 +619,38 @@ regind(t, n); return; } + } else if(n->op == OINDREG) { + if((v = n->xoffset) > -4096 && v < 4096) { + n->op = OREGISTER; + cgen(n, t); + t->xoffset += v; + n->op = OINDREG; + regind(t, n); + return; + } } lcgen(n, t); regind(t, n); } void +reglpcgen(Node *n, Node *nn, int f) +{ + Type *t; + + t = nn->type; + nn->type = types[TLONG]; + if(f) + reglcgen(n, nn, Z); + else { + regialloc(n, nn, Z); + lcgen(nn, n); + regind(n, nn); + } + nn->type = t; +} + +void lcgen(Node *n, Node *nn) { Prog *p1; @@ -1164,7 +672,12 @@ diag(n, "unknown op in lcgen: %O", n->op); break; } - gopcode(OADDR, n->type, n, nn); + nod = *n; + nod.op = OADDR; + nod.left = n; + nod.right = Z; + nod.type = types[TIND]; + gopcode(OAS, &nod, Z, nn); break; case OCOMMA: @@ -1205,7 +718,7 @@ int o; Prog *p1, *p2; Node *l, *r, nod, nod1; - long curs; + int32 curs; if(debug['g']) { prtree(nn, "boolgen lhs"); @@ -1217,29 +730,15 @@ switch(n->op) { default: + regalloc(&nod, n, nn); + cgen(n, &nod); o = ONE; if(true) - o = OEQ; - /* bad, 13 is address of external that becomes constant */ - if(n->addable >= INDEXED && n->addable != 13) { - if(typefd[n->type->etype]) { - regalloc(&nod1, n, Z); - gmove(nodfconst(0.0), &nod1); /* TO DO: FREGZERO */ - gopcode(o, n->type, n, &nod1); - regfree(&nod1); - } else - gopcode(o, n->type, n, nodconst(0)); - goto com; - } - regalloc(&nod, n, nn); - cgen(n, &nod); + o = comrel[relindex(o)]; if(typefd[n->type->etype]) { - regalloc(&nod1, n, Z); - gmove(nodfconst(0.0), &nod1); /* TO DO: FREGZERO */ - gopcode(o, n->type, &nod, &nod1); - regfree(&nod1); + gopcode(o, nodfconst(0), &nod, Z); } else - gopcode(o, n->type, &nod, nodconst(0)); + gopcode(o, nodconst(0), &nod, Z); regfree(&nod); goto com; @@ -1323,64 +822,53 @@ o = comrel[relindex(o)]; if(l->complex >= FNX && r->complex >= FNX) { regret(&nod, r); - cgen(r, &nod); + cgenrel(r, &nod); regsalloc(&nod1, r); - gmove(&nod, &nod1); + gopcode(OAS, &nod, Z, &nod1); regfree(&nod); nod = *n; nod.right = &nod1; boolgen(&nod, true, nn); break; } - if(immconst(l)) { + if(sconst(l)) { + regalloc(&nod, r, nn); + cgenrel(r, &nod); o = invrel[relindex(o)]; - /* bad, 13 is address of external that becomes constant */ - if(r->addable < INDEXED || r->addable == 13) { - regalloc(&nod, r, nn); - cgen(r, &nod); - gopcode(o, l->type, &nod, l); - regfree(&nod); - } else - gopcode(o, l->type, r, l); - goto com; - } - if(typefd[l->type->etype]) - o = invrel[relindex(logrel[relindex(o)])]; - if(l->complex >= r->complex) { - regalloc(&nod, l, nn); - cgen(l, &nod); - if(r->addable < INDEXED || hardconst(r) || typefd[l->type->etype]) { - regalloc(&nod1, r, Z); - cgen(r, &nod1); - gopcode(o, l->type, &nod, &nod1); - regfree(&nod1); - } else - gopcode(o, l->type, &nod, r); + gopcode(o, l, &nod, Z); regfree(&nod); goto com; } - regalloc(&nod, r, nn); - cgen(r, &nod); - if(l->addable < INDEXED || l->addable == 13 || hardconst(l)) { + if(sconst(r)) { + regalloc(&nod, l, nn); + cgenrel(l, &nod); + gopcode(o, r, &nod, Z); + regfree(&nod); + goto com; + } + if(l->complex >= r->complex) { + regalloc(&nod1, l, nn); + cgenrel(l, &nod1); + regalloc(&nod, r, Z); + cgenrel(r, &nod); + } else { + regalloc(&nod, r, nn); + cgenrel(r, &nod); regalloc(&nod1, l, Z); - cgen(l, &nod1); - if(typechl[l->type->etype] && ewidth[l->type->etype] <= ewidth[TINT]) - gopcode(o, types[TINT], &nod1, &nod); - else - gopcode(o, l->type, &nod1, &nod); - regfree(&nod1); - } else - gopcode(o, l->type, l, &nod); + cgenrel(l, &nod1); + } + gopcode(o, &nod, &nod1, Z); regfree(&nod); + regfree(&nod1); com: if(nn != Z) { p1 = p; - gmove(nodconst(1L), nn); + gopcode(OAS, nodconst(1), Z, nn); gbranch(OGOTO); p2 = p; patch(p1, pc); - gmove(nodconst(0L), nn); + gopcode(OAS, nodconst(0), Z, nn); patch(p2, pc); } break; @@ -1389,13 +877,13 @@ } void -sugen(Node *n, Node *nn, long w) +sugen(Node *n, Node *nn, int32 w) { Prog *p1; Node nod0, nod1, nod2, nod3, nod4, *l, *r; Type *t; - int c, mt, mo; - vlong o0, o1; + int32 pc1; + int i, m, c; if(n == Z || n->type == T) return; @@ -1417,36 +905,60 @@ goto copy; case OCONST: + if(n->type && typev[n->type->etype]) { + if(nn == Z) { + nullwarn(n->left, Z); + break; + } + + t = nn->type; + nn->type = types[TLONG]; + reglcgen(&nod1, nn, Z); + nn->type = t; + + if(isbigendian) + gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1); + else + gopcode(OAS, nod32const(n->vconst), Z, &nod1); + nod1.xoffset += SZ_LONG; + if(isbigendian) + gopcode(OAS, nod32const(n->vconst), Z, &nod1); + else + gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1); + + regfree(&nod1); + break; + } goto copy; case ODOT: l = n->left; sugen(l, nodrat, l->type->width); - if(nn == Z) - break; - warn(n, "non-interruptable temporary"); - nod1 = *nodrat; - r = n->right; - if(!r || r->op != OCONST) { - diag(n, "DOT and no offset"); - break; + if(nn != Z) { + warn(n, "non-interruptable temporary"); + nod1 = *nodrat; + r = n->right; + if(!r || r->op != OCONST) { + diag(n, "DOT and no offset"); + break; + } + nod1.xoffset += (int32)r->vconst; + nod1.type = n->type; + sugen(&nod1, nn, w); } - nod1.xoffset += (long)r->vconst; - nod1.type = n->type; - sugen(&nod1, nn, w); break; case OSTRUCT: /* * rewrite so lhs has no fn call */ - if(nn != Z && side(nn)) { + if(nn != Z && nn->complex >= FNX) { nod1 = *n; nod1.type = typ(TIND, n->type); regret(&nod2, &nod1); lcgen(nn, &nod2); regsalloc(&nod0, &nod1); - cgen(&nod2, &nod0); + gopcode(OAS, &nod2, Z, &nod0); regfree(&nod2); nod1 = *n; @@ -1477,7 +989,7 @@ nod0.op = OAS; nod0.type = t; nod0.left = &nod1; - nod0.right = nil; + nod0.right = l; nod1 = znode; nod1.op = OIND; @@ -1504,9 +1016,7 @@ acom(&nod0); xcom(&nod0); nod0.addable = 0; - nod0.right = l; - /* prtree(&nod0, "hand craft"); /* */ cgen(&nod0, Z); } break; @@ -1517,7 +1027,6 @@ sugen(n->right, n->left, w); break; } - sugen(n->right, nodrat, w); warn(n, "non-interruptable temporary"); sugen(nodrat, n->left, w); @@ -1560,35 +1069,9 @@ return; copy: - if(nn == Z) { - switch(n->op) { - case OASADD: - case OASSUB: - case OASAND: - case OASOR: - case OASXOR: - - case OASMUL: - case OASLMUL: - - - case OASASHL: - case OASASHR: - case OASLSHR: - break; - - case OPOSTINC: - case OPOSTDEC: - case OPREINC: - case OPREDEC: - break; - - default: - return; - } - } - - if(n->complex >= FNX && nn != nil && nn->complex >= FNX) { + if(nn == Z) + return; + if(n->complex >= FNX && nn->complex >= FNX) { t = nn->type; nn->type = types[TLONG]; regialloc(&nod1, nn, Z); @@ -1596,7 +1079,7 @@ regsalloc(&nod2, nn); nn->type = t; - gins(AMOVL, &nod1, &nod2); + gopcode(OAS, &nod1, Z, &nod2); regfree(&nod1); nod2.type = typ(TIND, t); @@ -1612,331 +1095,105 @@ return; } - if(w <= 32) { - c = cursafe; - if(n->left != Z && n->left->complex >= FNX - && n->right != Z && n->right->complex >= FNX) { - regsalloc(&nod1, n->right); - cgen(n->right, &nod1); - nod2 = *n; - nod2.right = &nod1; - cgen(&nod2, nn); - cursafe = c; - return; + w /= SZ_LONG; + if(w <= 2) { + if(n->complex > nn->complex) { + reglpcgen(&nod1, n, 1); + reglpcgen(&nod2, nn, 1); + } else { + reglpcgen(&nod2, nn, 1); + reglpcgen(&nod1, n, 1); } - if(w & 7) { - mt = TLONG; - mo = AMOVL; - } else { - mt = TVLONG; - mo = AMOVQ; + regalloc(&nod3, ®node, Z); + regalloc(&nod4, ®node, Z); + nod0 = *nodconst((1<complex > nn->complex) { - t = n->type; - n->type = types[mt]; - regalloc(&nod0, n, Z); - if(!vaddr(n, 0)) { - reglcgen(&nod1, n, Z); - n->type = t; - n = &nod1; + if(w == 2 && nod2.xoffset == 0) + gmovm(&nod0, &nod2, 0); + else { + gmove(&nod3, &nod2); + if(w == 2) { + nod2.xoffset += SZ_LONG; + gmove(&nod4, &nod2); } - else - n->type = t; - - t = nn->type; - nn->type = types[mt]; - if(!vaddr(nn, 0)) { - reglcgen(&nod2, nn, Z); - nn->type = t; - nn = &nod2; - } - else - nn->type = t; - } else { - t = nn->type; - nn->type = types[mt]; - regalloc(&nod0, nn, Z); - if(!vaddr(nn, 0)) { - reglcgen(&nod2, nn, Z); - nn->type = t; - nn = &nod2; - } - else - nn->type = t; - - t = n->type; - n->type = types[mt]; - if(!vaddr(n, 0)) { - reglcgen(&nod1, n, Z); - n->type = t; - n = &nod1; - } - else - n->type = t; } - o0 = n->xoffset; - o1 = nn->xoffset; - w /= ewidth[mt]; - while(--w >= 0) { - gins(mo, n, &nod0); - gins(mo, &nod0, nn); - n->xoffset += ewidth[mt]; - nn->xoffset += ewidth[mt]; - } - n->xoffset = o0; - nn->xoffset = o1; - if(nn == &nod2) - regfree(&nod2); - if(n == &nod1) - regfree(&nod1); - regfree(&nod0); + regfree(&nod1); + regfree(&nod2); + regfree(&nod3); + regfree(&nod4); return; } - /* botch, need to save in .safe */ - c = 0; if(n->complex > nn->complex) { - t = n->type; - n->type = types[TLONG]; - nodreg(&nod1, n, D_SI); - if(reg[D_SI]) { - gins(APUSHQ, &nod1, Z); - c |= 1; - reg[D_SI]++; - } - lcgen(n, &nod1); - n->type = t; - - t = nn->type; - nn->type = types[TLONG]; - nodreg(&nod2, nn, D_DI); - if(reg[D_DI]) { -warn(Z, "DI botch"); - gins(APUSHQ, &nod2, Z); - c |= 2; - reg[D_DI]++; - } - lcgen(nn, &nod2); - nn->type = t; + reglpcgen(&nod1, n, 0); + reglpcgen(&nod2, nn, 0); } else { - t = nn->type; - nn->type = types[TLONG]; - nodreg(&nod2, nn, D_DI); - if(reg[D_DI]) { -warn(Z, "DI botch"); - gins(APUSHQ, &nod2, Z); - c |= 2; - reg[D_DI]++; - } - lcgen(nn, &nod2); - nn->type = t; - - t = n->type; - n->type = types[TLONG]; - nodreg(&nod1, n, D_SI); - if(reg[D_SI]) { - gins(APUSHQ, &nod1, Z); - c |= 1; - reg[D_SI]++; - } - lcgen(n, &nod1); - n->type = t; - } - nodreg(&nod3, n, D_CX); - if(reg[D_CX]) { - gins(APUSHQ, &nod3, Z); - c |= 4; - reg[D_CX]++; - } - gins(AMOVL, nodconst(w/SZ_INT), &nod3); - gins(ACLD, Z, Z); - gins(AREP, Z, Z); - gins(AMOVSL, Z, Z); - if(c & 4) { - gins(APOPQ, Z, &nod3); - reg[D_CX]--; - } - if(c & 2) { - gins(APOPQ, Z, &nod2); - reg[nod2.reg]--; - } - if(c & 1) { - gins(APOPQ, Z, &nod1); - reg[nod1.reg]--; - } -} - -/* - * TO DO - */ -void -layout(Node *f, Node *t, int c, int cv, Node *cn) -{ - Node t1, t2; - - while(c > 3) { - layout(f, t, 2, 0, Z); - c -= 2; + reglpcgen(&nod2, nn, 0); + reglpcgen(&nod1, n, 0); } - regalloc(&t1, &lregnode, Z); - regalloc(&t2, &lregnode, Z); - if(c > 0) { - gmove(f, &t1); - f->xoffset += SZ_INT; + m = 0; + for(c = 0; c < w && c < 4; c++) { + i = tmpreg(); + if (i == 0) + break; + reg[i]++; + m |= 1< 1) { - gmove(f, &t2); - f->xoffset += SZ_INT; + nod4 = *(nodconst(m)); + if(w < 3*c) { + for (; w>c; w-=c) { + gmovm(&nod1, &nod4, 1); + gmovm(&nod4, &nod2, 1); + } + goto out; } - if(c > 0) { - gmove(&t1, t); - t->xoffset += SZ_INT; + + regalloc(&nod3, ®node, Z); + gopcode(OAS, nodconst(w/c), Z, &nod3); + w %= c; + + pc1 = pc; + gmovm(&nod1, &nod4, 1); + gmovm(&nod4, &nod2, 1); + + gopcode(OSUB, nodconst(1), Z, &nod3); + gopcode(OEQ, nodconst(0), &nod3, Z); + p->as = ABGT; + patch(p, pc1); + regfree(&nod3); + +out: + if (w) { + i = 0; + while (c>w) { + while ((m&(1< 2) { - gmove(f, &t1); - f->xoffset += SZ_INT; - } - if(c > 1) { - gmove(&t2, t); - t->xoffset += SZ_INT; - } - if(c > 2) { - gmove(&t1, t); - t->xoffset += SZ_INT; - } - regfree(&t1); - regfree(&t2); + i = 0; + do { + while ((m&(1<0); + regfree(&nod1); + regfree(&nod2); } - -/* - * constant is not vlong or fits as 32-bit signed immediate - */ -int -immconst(Node *n) -{ - long v; - - if(n->op != OCONST || !typechlpv[n->type->etype]) - return 0; - if(typechl[n->type->etype]) - return 1; - v = n->vconst; - return n->vconst == (vlong)v; -} - -/* - * if a constant and vlong, doesn't fit as 32-bit signed immediate - */ -int -hardconst(Node *n) -{ - return n->op == OCONST && !immconst(n); -} - -/* - * casting up to t2 covers an intermediate cast to t1 - */ -int -castup(Type *t1, Type *t2) -{ - int ft; - - if(!nilcast(t1, t2)) - return 0; - /* known to be small to large */ - ft = t1->etype; - switch(t2->etype){ - case TINT: - case TLONG: - return ft == TLONG || ft == TINT || ft == TSHORT || ft == TCHAR; - case TUINT: - case TULONG: - return ft == TULONG || ft == TUINT || ft == TUSHORT || ft == TUCHAR; - case TVLONG: - return ft == TLONG || ft == TINT || ft == TSHORT; - case TUVLONG: - return ft == TULONG || ft == TUINT || ft == TUSHORT; - } - return 0; -} - -void -zeroregm(Node *n) -{ - gins(AMOVL, nodconst(0), n); -} - -/* do we need to load the address of a vlong? */ -int -vaddr(Node *n, int a) -{ - switch(n->op) { - case ONAME: - if(a) - return 1; - return !(n->class == CEXTERN || n->class == CGLOBL || n->class == CSTATIC); - - case OCONST: - case OREGISTER: - case OINDREG: - return 1; - } - return 0; -} - -long -hi64v(Node *n) -{ - if(align(0, types[TCHAR], Aarg1)) /* isbigendian */ - return (long)(n->vconst) & ~0L; - else - return (long)((uvlong)n->vconst>>32) & ~0L; -} - -long -lo64v(Node *n) -{ - if(align(0, types[TCHAR], Aarg1)) /* isbigendian */ - return (long)((uvlong)n->vconst>>32) & ~0L; - else - return (long)(n->vconst) & ~0L; -} - -Node * -hi64(Node *n) -{ - return nodconst(hi64v(n)); -} - -Node * -lo64(Node *n) -{ - return nodconst(lo64v(n)); -} - -int -cond(int op) -{ - switch(op) { - case OANDAND: - case OOROR: - case ONOT: - return 1; - - case OEQ: - case ONE: - case OLE: - case OLT: - case OGE: - case OGT: - case OHI: - case OHS: - case OLO: - case OLS: - return 1; - } - return 0; -} diff -r d8d00747375b sys/src/cmd/6c/div.c --- a/sys/src/cmd/6c/div.c Thu Sep 29 03:00:00 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,206 +0,0 @@ -#include "gc.h" - -/* - * Based on: Granlund, T.; Montgomery, P.L. - * "Division by Invariant Integers using Multiplication". - * SIGPLAN Notices, Vol. 29, June 1994, page 61. - */ - -#define TN(n) ((uvlong)1 << (n)) -#define T31 TN(31) -#define T32 TN(32) - -int -multiplier(ulong d, int p, uvlong *mp) -{ - int l; - uvlong mlo, mhi, tlo, thi; - - l = topbit(d - 1) + 1; - mlo = (((TN(l) - d) << 32) / d) + T32; - if(l + p == 64) - mhi = (((TN(l) + 1 - d) << 32) / d) + T32; - else - mhi = (TN(32 + l) + TN(32 + l - p)) / d; - /*assert(mlo < mhi);*/ - while(l > 0) { - tlo = mlo >> 1; - thi = mhi >> 1; - if(tlo == thi) - break; - mlo = tlo; - mhi = thi; - l--; - } - *mp = mhi; - return l; -} - -int -sdiv(ulong d, ulong *mp, int *sp) -{ - int s; - uvlong m; - - s = multiplier(d, 32 - 1, &m); - *mp = m; - *sp = s; - if(m >= T31) - return 1; - else - return 0; -} - -int -udiv(ulong d, ulong *mp, int *sp, int *pp) -{ - int p, s; - uvlong m; - - s = multiplier(d, 32, &m); - p = 0; - if(m >= T32) { - while((d & 1) == 0) { - d >>= 1; - p++; - } - s = multiplier(d, 32 - p, &m); - } - *mp = m; - *pp = p; - if(m >= T32) { - /*assert(p == 0);*/ - *sp = s - 1; - return 1; - } - else { - *sp = s; - return 0; - } -} - -void -sdivgen(Node *l, Node *r, Node *ax, Node *dx) -{ - int a, s; - ulong m; - vlong c; - - c = r->vconst; - if(c < 0) - c = -c; - a = sdiv(c, &m, &s); -//print("a=%d i=%ld s=%d m=%lux\n", a, (long)r->vconst, s, m); - gins(AMOVL, nodconst(m), ax); - gins(AIMULL, l, Z); - gins(AMOVL, l, ax); - if(a) - gins(AADDL, ax, dx); - gins(ASHRL, nodconst(31), ax); - gins(ASARL, nodconst(s), dx); - gins(AADDL, ax, dx); - if(r->vconst < 0) - gins(ANEGL, Z, dx); -} - -void -udivgen(Node *l, Node *r, Node *ax, Node *dx) -{ - int a, s, t; - ulong m; - Node nod; - - a = udiv(r->vconst, &m, &s, &t); -//print("a=%ud i=%ld p=%d s=%d m=%lux\n", a, (long)r->vconst, t, s, m); - if(t != 0) { - gins(AMOVL, l, ax); - gins(ASHRL, nodconst(t), ax); - gins(AMOVL, nodconst(m), dx); - gins(AMULL, dx, Z); - } - else if(a) { - if(l->op != OREGISTER) { - regalloc(&nod, l, Z); - gins(AMOVL, l, &nod); - l = &nod; - } - gins(AMOVL, nodconst(m), ax); - gins(AMULL, l, Z); - gins(AADDL, l, dx); - gins(ARCRL, nodconst(1), dx); - if(l == &nod) - regfree(l); - } - else { - gins(AMOVL, nodconst(m), ax); - gins(AMULL, l, Z); - } - if(s != 0) - gins(ASHRL, nodconst(s), dx); -} - -void -sext(Node *d, Node *s, Node *l) -{ - if(s->reg == D_AX && !nodreg(d, Z, D_DX)) { - reg[D_DX]++; - gins(ACDQ, Z, Z); - } - else { - regalloc(d, l, Z); - gins(AMOVL, s, d); - gins(ASARL, nodconst(31), d); - } -} - -void -sdiv2(long c, int v, Node *l, Node *n) -{ - Node nod; - - if(v > 0) { - if(v > 1) { - sext(&nod, n, l); - gins(AANDL, nodconst((1 << v) - 1), &nod); - gins(AADDL, &nod, n); - regfree(&nod); - } - else { - gins(ACMPL, n, nodconst(0x80000000)); - gins(ASBBL, nodconst(-1), n); - } - gins(ASARL, nodconst(v), n); - } - if(c < 0) - gins(ANEGL, Z, n); -} - -void -smod2(long c, int v, Node *l, Node *n) -{ - Node nod; - - if(c == 1) { - zeroregm(n); - return; - } - - sext(&nod, n, l); - if(v == 0) { - zeroregm(n); - gins(AXORL, &nod, n); - gins(ASUBL, &nod, n); - } - else if(v > 1) { - gins(AANDL, nodconst((1 << v) - 1), &nod); - gins(AADDL, &nod, n); - gins(AANDL, nodconst((1 << v) - 1), n); - gins(ASUBL, &nod, n); - } - else { - gins(AANDL, nodconst(1), n); - gins(AXORL, &nod, n); - gins(ASUBL, &nod, n); - } - regfree(&nod); -} diff -r d8d00747375b sys/src/cmd/6c/enam.c --- a/sys/src/cmd/6c/enam.c Thu Sep 29 03:00:00 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,669 +0,0 @@ -char* anames[] = -{ - "XXX", - "AAA", - "AAD", - "AAM", - "AAS", - "ADCB", - "ADCL", - "ADCW", - "ADDB", - "ADDL", - "ADDW", - "ADJSP", - "ANDB", - "ANDL", - "ANDW", - "ARPL", - "BOUNDL", - "BOUNDW", - "BSFL", - "BSFW", - "BSRL", - "BSRW", - "BTL", - "BTW", - "BTCL", - "BTCW", - "BTRL", - "BTRW", - "BTSL", - "BTSW", - "BYTE", - "CALL", - "CLC", - "CLD", - "CLI", - "CLTS", - "CMC", - "CMPB", - "CMPL", - "CMPW", - "CMPSB", - "CMPSL", - "CMPSW", - "DAA", - "DAS", - "DATA", - "DECB", - "DECL", - "DECQ", - "DECW", - "DIVB", - "DIVL", - "DIVW", - "ENTER", - "GLOBL", - "GOK", - "HISTORY", - "HLT", - "IDIVB", - "IDIVL", - "IDIVW", - "IMULB", - "IMULL", - "IMULW", - "INB", - "INL", - "INW", - "INCB", - "INCL", - "INCQ", - "INCW", - "INSB", - "INSL", - "INSW", - "INT", - "INTO", - "IRETL", - "IRETW", - "JCC", - "JCS", - "JCXZ", - "JEQ", - "JGE", - "JGT", - "JHI", - "JLE", - "JLS", - "JLT", - "JMI", - "JMP", - "JNE", - "JOC", - "JOS", - "JPC", - "JPL", - "JPS", - "LAHF", - "LARL", - "LARW", - "LEAL", - "LEAW", - "LEAVEL", - "LEAVEW", - "LOCK", - "LODSB", - "LODSL", - "LODSW", - "LONG", - "LOOP", - "LOOPEQ", - "LOOPNE", - "LSLL", - "LSLW", - "MOVB", - "MOVL", - "MOVW", - "MOVBLSX", - "MOVBLZX", - "MOVBQSX", - "MOVBQZX", - "MOVBWSX", - "MOVBWZX", - "MOVWLSX", - "MOVWLZX", - "MOVWQSX", - "MOVWQZX", - "MOVSB", - "MOVSL", - "MOVSW", - "MULB", - "MULL", - "MULW", - "NAME", - "NEGB", - "NEGL", - "NEGW", - "NOP", - "NOTB", - "NOTL", - "NOTW", - "ORB", - "ORL", - "ORW", - "OUTB", - "OUTL", - "OUTW", - "OUTSB", - "OUTSL", - "OUTSW", - "POPAL", - "POPAW", - "POPFL", - "POPFW", - "POPL", - "POPW", - "PUSHAL", - "PUSHAW", - "PUSHFL", - "PUSHFW", - "PUSHL", - "PUSHW", - "RCLB", - "RCLL", - "RCLW", - "RCRB", - "RCRL", - "RCRW", - "REP", - "REPN", - "RET", - "ROLB", - "ROLL", - "ROLW", - "RORB", - "RORL", - "RORW", - "SAHF", - "SALB", - "SALL", - "SALW", - "SARB", - "SARL", - "SARW", - "SBBB", - "SBBL", - "SBBW", - "SCASB", - "SCASL", - "SCASW", - "SETCC", - "SETCS", - "SETEQ", - "SETGE", - "SETGT", - "SETHI", - "SETLE", - "SETLS", - "SETLT", - "SETMI", - "SETNE", - "SETOC", - "SETOS", - "SETPC", - "SETPL", - "SETPS", - "CDQ", - "CWD", - "SHLB", - "SHLL", - "SHLW", - "SHRB", - "SHRL", - "SHRW", - "STC", - "STD", - "STI", - "STOSB", - "STOSL", - "STOSW", - "SUBB", - "SUBL", - "SUBW", - "SYSCALL", - "TESTB", - "TESTL", - "TESTW", - "TEXT", - "VERR", - "VERW", - "WAIT", - "WORD", - "XCHGB", - "XCHGL", - "XCHGW", - "XLAT", - "XORB", - "XORL", - "XORW", - "FMOVB", - "FMOVBP", - "FMOVD", - "FMOVDP", - "FMOVF", - "FMOVFP", - "FMOVL", - "FMOVLP", - "FMOVV", - "FMOVVP", - "FMOVW", - "FMOVWP", - "FMOVX", - "FMOVXP", - "FCOMB", - "FCOMBP", - "FCOMD", - "FCOMDP", - "FCOMDPP", - "FCOMF", - "FCOMFP", - "FCOML", - "FCOMLP", - "FCOMW", - "FCOMWP", - "FUCOM", - "FUCOMP", - "FUCOMPP", - "FADDDP", - "FADDW", - "FADDL", - "FADDF", - "FADDD", - "FMULDP", - "FMULW", - "FMULL", - "FMULF", - "FMULD", - "FSUBDP", - "FSUBW", - "FSUBL", - "FSUBF", - "FSUBD", - "FSUBRDP", - "FSUBRW", - "FSUBRL", - "FSUBRF", - "FSUBRD", - "FDIVDP", - "FDIVW", - "FDIVL", - "FDIVF", - "FDIVD", - "FDIVRDP", - "FDIVRW", - "FDIVRL", - "FDIVRF", - "FDIVRD", - "FXCHD", - "FFREE", - "FLDCW", - "FLDENV", - "FRSTOR", - "FSAVE", - "FSTCW", - "FSTENV", - "FSTSW", - "F2XM1", - "FABS", - "FCHS", - "FCLEX", - "FCOS", - "FDECSTP", - "FINCSTP", - "FINIT", - "FLD1", - "FLDL2E", - "FLDL2T", - "FLDLG2", - "FLDLN2", - "FLDPI", - "FLDZ", - "FNOP", - "FPATAN", - "FPREM", - "FPREM1", - "FPTAN", - "FRNDINT", - "FSCALE", - "FSIN", - "FSINCOS", - "FSQRT", - "FTST", - "FXAM", - "FXTRACT", - "FYL2X", - "FYL2XP1", - "END", - "DYNT", - "INIT", - "SIGNAME", - "CMPXCHGB", - "CMPXCHGL", - "CMPXCHGW", - "CMPXCHG8B", - "CPUID", - "INVD", - "INVLPG", - "LFENCE", - "MFENCE", - "MOVNTIL", - "RDMSR", - "RDPMC", - "RDTSC", - "RSM", - "SFENCE", - "SYSRET", - "WBINVD", - "WRMSR", - "XADDB", - "XADDL", - "XADDW", - "CMOVLCC", - "CMOVLCS", - "CMOVLEQ", - "CMOVLGE", - "CMOVLGT", - "CMOVLHI", - "CMOVLLE", - "CMOVLLS", - "CMOVLLT", - "CMOVLMI", - "CMOVLNE", - "CMOVLOC", - "CMOVLOS", - "CMOVLPC", - "CMOVLPL", - "CMOVLPS", - "CMOVQCC", - "CMOVQCS", - "CMOVQEQ", - "CMOVQGE", - "CMOVQGT", - "CMOVQHI", - "CMOVQLE", - "CMOVQLS", - "CMOVQLT", - "CMOVQMI", - "CMOVQNE", - "CMOVQOC", - "CMOVQOS", - "CMOVQPC", - "CMOVQPL", - "CMOVQPS", - "CMOVWCC", - "CMOVWCS", - "CMOVWEQ", - "CMOVWGE", - "CMOVWGT", - "CMOVWHI", - "CMOVWLE", - "CMOVWLS", - "CMOVWLT", - "CMOVWMI", - "CMOVWNE", - "CMOVWOC", - "CMOVWOS", - "CMOVWPC", - "CMOVWPL", - "CMOVWPS", - "ADCQ", - "ADDQ", - "ANDQ", - "BSFQ", - "BSRQ", - "BTCQ", - "BTQ", - "BTRQ", - "BTSQ", - "CMPQ", - "CMPSQ", - "CMPXCHGQ", - "CQO", - "DIVQ", - "IDIVQ", - "IMULQ", - "IRETQ", - "LEAQ", - "LEAVEQ", - "LODSQ", - "MOVQ", - "MOVLQSX", - "MOVLQZX", - "MOVNTIQ", - "MOVSQ", - "MULQ", - "NEGQ", - "NOTQ", - "ORQ", - "POPFQ", - "POPQ", - "PUSHFQ", - "PUSHQ", - "RCLQ", - "RCRQ", - "ROLQ", - "RORQ", - "QUAD", - "SALQ", - "SARQ", - "SBBQ", - "SCASQ", - "SHLQ", - "SHRQ", - "STOSQ", - "SUBQ", - "TESTQ", - "XADDQ", - "XCHGQ", - "XORQ", - "ADDPD", - "ADDPS", - "ADDSD", - "ADDSS", - "ANDNPD", - "ANDNPS", - "ANDPD", - "ANDPS", - "CMPPD", - "CMPPS", - "CMPSD", - "CMPSS", - "COMISD", - "COMISS", - "CVTPD2PL", - "CVTPD2PS", - "CVTPL2PD", - "CVTPL2PS", - "CVTPS2PD", - "CVTPS2PL", - "CVTSD2SL", - "CVTSD2SQ", - "CVTSD2SS", - "CVTSL2SD", - "CVTSL2SS", - "CVTSQ2SD", - "CVTSQ2SS", - "CVTSS2SD", - "CVTSS2SL", - "CVTSS2SQ", - "CVTTPD2PL", - "CVTTPS2PL", - "CVTTSD2SL", - "CVTTSD2SQ", - "CVTTSS2SL", - "CVTTSS2SQ", - "DIVPD", - "DIVPS", - "DIVSD", - "DIVSS", - "EMMS", - "FXRSTOR", - "FXRSTOR64", - "FXSAVE", - "FXSAVE64", - "LDMXCSR", - "MASKMOVOU", - "MASKMOVQ", - "MAXPD", - "MAXPS", - "MAXSD", - "MAXSS", - "MINPD", - "MINPS", - "MINSD", - "MINSS", - "MOVAPD", - "MOVAPS", - "MOVOU", - "MOVHLPS", - "MOVHPD", - "MOVHPS", - "MOVLHPS", - "MOVLPD", - "MOVLPS", - "MOVMSKPD", - "MOVMSKPS", - "MOVNTO", - "MOVNTPD", - "MOVNTPS", - "MOVNTQ", - "MOVO", - "MOVQOZX", - "MOVSD", - "MOVSS", - "MOVUPD", - "MOVUPS", - "MULPD", - "MULPS", - "MULSD", - "MULSS", - "ORPD", - "ORPS", - "PACKSSLW", - "PACKSSWB", - "PACKUSWB", - "PADDB", - "PADDL", - "PADDQ", - "PADDSB", - "PADDSW", - "PADDUSB", - "PADDUSW", - "PADDW", - "PANDB", - "PANDL", - "PANDSB", - "PANDSW", - "PANDUSB", - "PANDUSW", - "PANDW", - "PAND", - "PANDN", - "PAVGB", - "PAVGW", - "PCMPEQB", - "PCMPEQL", - "PCMPEQW", - "PCMPGTB", - "PCMPGTL", - "PCMPGTW", - "PEXTRW", - "PFACC", - "PFADD", - "PFCMPEQ", - "PFCMPGE", - "PFCMPGT", - "PFMAX", - "PFMIN", - "PFMUL", - "PFNACC", - "PFPNACC", - "PFRCP", - "PFRCPIT1", - "PFRCPI2T", - "PFRSQIT1", - "PFRSQRT", - "PFSUB", - "PFSUBR", - "PINSRW", - "PMADDWL", - "PMAXSW", - "PMAXUB", - "PMINSW", - "PMINUB", - "PMOVMSKB", - "PMULHRW", - "PMULHUW", - "PMULHW", - "PMULLW", - "PMULULQ", - "POR", - "PSADBW", - "PSHUFHW", - "PSHUFL", - "PSHUFLW", - "PSHUFW", - "PSLLO", - "PSLLL", - "PSLLQ", - "PSLLW", - "PSRAL", - "PSRAW", - "PSRLO", - "PSRLL", - "PSRLQ", - "PSRLW", - "PSUBB", - "PSUBL", - "PSUBQ", - "PSUBSB", - "PSUBSW", - "PSUBUSB", - "PSUBUSW", - "PSUBW", - "PSWAPL", - "PUNPCKHBW", - "PUNPCKHLQ", - "PUNPCKHQDQ", - "PUNPCKHWL", - "PUNPCKLBW", - "PUNPCKLLQ", - "PUNPCKLQDQ", - "PUNPCKLWL", - "PXOR", - "RCPPS", - "RCPSS", - "RSQRTPS", - "RSQRTSS", - "SHUFPD", - "SHUFPS", - "SQRTPD", - "SQRTPS", - "SQRTSD", - "SQRTSS", - "STMXCSR", - "SUBPD", - "SUBPS", - "SUBSD", - "SUBSS", - "UCOMISD", - "UCOMISS", - "UNPCKHPD", - "UNPCKHPS", - "UNPCKLPD", - "UNPCKLPS", - "XORPD", - "XORPS", - "PF2IW", - "PF2IL", - "PI2FW", - "PI2FL", - "RETFW", - "RETFL", - "RETFQ", - "SWAPGS", - "MODE", - "LAST", -}; diff -r d8d00747375b sys/src/cmd/6c/gc.h --- a/sys/src/cmd/6c/gc.h Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/6c/gc.h Mon Nov 14 17:35:25 2011 +0100 @@ -1,15 +1,46 @@ +// Inferno utils/5c/gc.h +// http://code.google.com/p/inferno-os/source/browse/utils/5c/gc.h +// +// 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 #include "../cc/cc.h" -#include "../6c/6.out.h" +#include "../5l/5.out.h" /* - * 6c/amd64 - * Intel 386 with AMD64 extensions + * 5c/arm + * Arm 7500 */ #define SZ_CHAR 1 #define SZ_SHORT 2 #define SZ_INT 4 #define SZ_LONG 4 -#define SZ_IND 8 +#define SZ_IND 4 #define SZ_FLOAT 4 #define SZ_VLONG 8 #define SZ_DOUBLE 8 @@ -19,31 +50,28 @@ typedef struct Prog Prog; typedef struct Case Case; typedef struct C1 C1; +typedef struct Multab Multab; +typedef struct Hintab Hintab; typedef struct Var Var; typedef struct Reg Reg; typedef struct Rgn Rgn; -typedef struct Renv Renv; -EXTERN struct -{ - Node* regtree; - Node* basetree; - short scale; - short reg; - short ptr; -} idx; + +#define R0ISZERO 0 struct Adr { - vlong offset; + int32 offset; + int32 offset2; double dval; char sval[NSNAME]; + Ieee ieee; Sym* sym; - uchar type; - uchar index; - uchar etype; - uchar scale; /* doubles as width in DATA op */ + char type; + uchar reg; + char name; + char etype; }; #define A ((Adr*)0) @@ -53,16 +81,18 @@ Adr from; Adr to; Prog* link; - long lineno; - short as; + int32 lineno; + char as; + uchar reg; + uchar scond; }; #define P ((Prog*)0) struct Case { Case* link; - vlong val; - long label; + int32 val; + int32 label; char def; char isv; }; @@ -70,13 +100,25 @@ struct C1 { - vlong val; - long label; + int32 val; + int32 label; +}; + +struct Multab +{ + int32 val; + char code[20]; +}; + +struct Hintab +{ + ushort val; + char hint[10]; }; struct Var { - vlong offset; + int32 offset; Sym* sym; char name; char etype; @@ -84,8 +126,8 @@ struct Reg { - long pc; - long rpo; /* reverse post ordering */ + int32 pc; + int32 rpo; /* reverse post ordering */ Bits set; Bits use1; @@ -98,11 +140,12 @@ Bits regdiff; Bits act; - long regu; - long loop; /* could be shorter */ + int32 regu; + int32 loop; /* could be shorter */ + Reg* log5; - long active; + int32 active; Reg* p1; Reg* p2; @@ -114,14 +157,6 @@ }; #define R ((Reg*)0) -struct Renv -{ - int safe; - Node base; - Node* saved; - Node* scope; -}; - #define NRGN 600 struct Rgn { @@ -131,36 +166,38 @@ short regno; }; -EXTERN long breakpc; -EXTERN long nbreak; +EXTERN int32 breakpc; +EXTERN int32 nbreak; EXTERN Case* cases; EXTERN Node constnode; EXTERN Node fconstnode; -EXTERN Node vconstnode; -EXTERN long continpc; -EXTERN long curarg; -EXTERN long cursafe; +EXTERN int32 continpc; +EXTERN int32 curarg; +EXTERN int32 cursafe; EXTERN Prog* firstp; +EXTERN int32 isbigendian; EXTERN Prog* lastp; -EXTERN long maxargsafe; +EXTERN int32 maxargsafe; EXTERN int mnstring; +EXTERN Multab multab[20]; +EXTERN int retok; +extern int hintabsize; EXTERN Node* nodrat; EXTERN Node* nodret; EXTERN Node* nodsafe; -EXTERN long nrathole; -EXTERN long nstring; +EXTERN int32 nrathole; +EXTERN int32 nstring; EXTERN Prog* p; -EXTERN long pc; -EXTERN Node lregnode; -EXTERN Node qregnode; +EXTERN int32 pc; +EXTERN Node regnode; EXTERN char string[NSNAME]; EXTERN Sym* symrathole; EXTERN Node znode; EXTERN Prog zprog; -EXTERN int reg[D_NONE]; -EXTERN long exregoffset; -EXTERN long exfregoffset; -EXTERN uchar typechlpv[NTYPE]; +EXTERN char reg[NREG+NFREG]; +EXTERN int32 exregoffset; +EXTERN int32 exfregoffset; +EXTERN int suppress; #define BLOAD(r) band(bnot(r->refbehind), r->refahead) #define BSTORE(r) band(bnot(r->calbehind), r->calahead) @@ -169,7 +206,7 @@ #define bset(a,n) ((a).b[(n)/32]&(1L<<(n)%32)) -#define CLOAD 5 +#define CLOAD 4 #define CREF 5 #define CINF 1000 #define LOOP 3 @@ -184,22 +221,22 @@ EXTERN Bits consts; EXTERN Bits addrs; -EXTERN long regbits; -EXTERN long exregbits; +EXTERN int32 regbits; +EXTERN int32 exregbits; EXTERN int change; -EXTERN int suppress; EXTERN Reg* firstr; EXTERN Reg* lastr; EXTERN Reg zreg; EXTERN Reg* freer; EXTERN Var var[NVAR]; -EXTERN long* idom; +EXTERN int32* idom; EXTERN Reg** rpo2r; -EXTERN long maxnr; +EXTERN int32 maxnr; extern char* anames[]; +extern Hintab hintab[]; /* * sgen.c @@ -209,30 +246,21 @@ void noretval(int); void usedset(Node*, int); void xcom(Node*); -void indx(Node*); int bcomplex(Node*, Node*); +Prog* gtext(Sym*, int32); +vlong argsize(void); /* * cgen.c */ -void zeroregm(Node*); void cgen(Node*, Node*); void reglcgen(Node*, Node*, Node*); void lcgen(Node*, Node*); void bcgen(Node*, int); void boolgen(Node*, int, Node*); -void sugen(Node*, Node*, long); -int needreg(Node*, int); -int hardconst(Node*); -int immconst(Node*); - -/* - * cgen64.c - */ -int vaddr(Node*, int); -void loadpair(Node*, Node*); -int cgen64(Node*, Node*); -void testv(Node*, int); +void sugen(Node*, Node*, int32); +void layout(Node*, Node*, int, int, Node*); +void cgenrel(Node*, Node*); /* * txt.c @@ -242,12 +270,12 @@ void nextpc(void); void gargs(Node*, Node*, Node*); void garg1(Node*, Node*, Node*, int, Node**); -Node* nodconst(long); +Node* nodconst(int32); +Node* nod32const(vlong); Node* nodfconst(double); -Node* nodgconst(vlong, Type*); -int nodreg(Node*, Node*, int); -int isreg(Node*, int); +void nodreg(Node*, Node*, int); void regret(Node*, Node*); +int tmpreg(void); void regalloc(Node*, Node*, Node*); void regfree(Node*); void regialloc(Node*, Node*, Node*); @@ -256,15 +284,18 @@ void regaalloc(Node*, Node*); void regind(Node*, Node*); void gprep(Node*, Node*); +void raddr(Node*, Prog*); void naddr(Node*, Adr*); -void gcmp(int, Node*, vlong); +void gmovm(Node*, Node*, int); void gmove(Node*, Node*); +void gmover(Node*, Node*); void gins(int a, Node*, Node*); -void gopcode(int, Type*, Node*, Node*); +void gopcode(int, Node*, Node*, Node*); int samaddr(Node*, Node*); void gbranch(int); -void patch(Prog*, long); +void patch(Prog*, int32); int sconst(Node*); +int sval(int32); void gpseudo(int, Sym*, Node*); /* @@ -272,14 +303,13 @@ */ int swcmp(const void*, const void*); void doswit(Node*); -void swit1(C1*, int, long, Node*); -void casf(void); +void swit1(C1*, int, int32, Node*); +void newcase(void); void bitload(Node*, Node*, Node*, Node*, Node*); void bitstore(Node*, Node*, Node*, Node*, Node*); -long outstring(char*, long); +int mulcon(Node*, Node*); +Multab* mulcon0(int32); void nullwarn(Node*, Node*); -void sextern(Sym*, Node*, long, long); -void gextern(Sym*, Node*, long, long); void outcode(void); void ieeedtod(Ieee*, double); @@ -291,9 +321,9 @@ int Aconv(Fmt*); int Dconv(Fmt*); int Sconv(Fmt*); +int Nconv(Fmt*); +int Bconv(Fmt*); int Rconv(Fmt*); -int Xconv(Fmt*); -int Bconv(Fmt*); /* * reg.c @@ -302,14 +332,14 @@ int rcmp(const void*, const void*); void regopt(Prog*); void addmove(Reg*, int, int, int); -Bits mkvar(Reg*, Adr*); +Bits mkvar(Adr*, int); void prop(Reg*, Bits, Bits); -void loopit(Reg*, long); +void loopit(Reg*, int32); void synch(Reg*, Bits); -ulong allreg(ulong, Rgn*); +uint32 allreg(uint32, Rgn*); void paint1(Reg*, int); -ulong paint2(Reg*, int); -void paint3(Reg*, int, long, int); +uint32 paint2(Reg*, int); +void paint3(Reg*, int, int32, int); void addreg(Adr*, int); /* @@ -320,62 +350,35 @@ Reg* uniqp(Reg*); Reg* uniqs(Reg*); int regtyp(Adr*); +int regzer(Adr*); int anyvar(Adr*); int subprop(Reg*); int copyprop(Reg*); +int shiftprop(Reg*); +void constprop(Adr*, Adr*, Reg*); int copy1(Adr*, Adr*, Reg*, int); int copyu(Prog*, Adr*, Adr*); int copyas(Adr*, Adr*); int copyau(Adr*, Adr*); +int copyau1(Prog*, Adr*); int copysub(Adr*, Adr*, Adr*, int); int copysub1(Prog*, Adr*, Adr*, int); -long RtoB(int); -long FtoB(int); -int BtoR(long); -int BtoF(long); +int32 RtoB(int); +int32 FtoB(int); +int BtoR(int32); +int BtoF(int32); -#define D_HI D_NONE -#define D_LO D_NONE - -#define isregtype(t) ((t)>= D_AX && (t)<=D_R15) - -/* - * bound - */ -void comtarg(void); - -/* - * com64 - */ -int cond(int); -int com64(Node*); -void com64init(void); -void bool64(Node*); -long lo64v(Node*); -long hi64v(Node*); -Node* lo64(Node*); -Node* hi64(Node*); - -/* - * div/mul - */ -void sdivgen(Node*, Node*, Node*, Node*); -void udivgen(Node*, Node*, Node*, Node*); -void sdiv2(long, int, Node*, Node*); -void smod2(long, int, Node*, Node*); -void mulgen(Type*, Node*, Node*); -void genmuladd(Node*, Node*, int, Node*); -void shiftit(Type*, Node*, Node*); +void predicate(void); +int isbranch(Prog *); +int predicable(Prog *p); +int modifiescpsr(Prog *p); #pragma varargck type "A" int #pragma varargck type "B" Bits #pragma varargck type "D" Adr* +#pragma varargck type "N" Adr* +#pragma varargck type "R" Adr* #pragma varargck type "P" Prog* -#pragma varargck type "R" int #pragma varargck type "S" char* - -#define D_X7 (D_X0+7) - -void fgopcode(int, Node*, Node*, int, int); diff -r d8d00747375b sys/src/cmd/6c/list.c --- a/sys/src/cmd/6c/list.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/6c/list.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,4 +1,35 @@ -#define EXTERN +// Inferno utils/5c/list.c +// http://code.google.com/p/inferno-os/source/browse/utils/5c/list.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. + + +#define EXTERN #include "gc.h" void @@ -6,9 +37,10 @@ { fmtinstall('A', Aconv); - fmtinstall('B', Bconv); fmtinstall('P', Pconv); fmtinstall('S', Sconv); + fmtinstall('N', Nconv); + fmtinstall('B', Bconv); fmtinstall('D', Dconv); fmtinstall('R', Rconv); } @@ -27,7 +59,7 @@ if(str[0]) strcat(str, " "); if(var[i].sym == S) { - sprint(ss, "$%lld", var[i].offset); + sprint(ss, "$%d", var[i].offset); s = ss; } else s = var[i].sym->name; @@ -39,255 +71,182 @@ return fmtstrcpy(fp, str); } +char *extra [] = { + ".EQ", ".NE", ".CS", ".CC", + ".MI", ".PL", ".VS", ".VC", + ".HI", ".LS", ".GE", ".LT", + ".GT", ".LE", "", ".NV", +}; + int Pconv(Fmt *fp) { - char str[STRINGSZ]; + char str[STRINGSZ], sc[20]; Prog *p; + int a, s; p = va_arg(fp->args, Prog*); - if(p->as == ADATA) - sprint(str, " %A %D/%d,%D", - p->as, &p->from, p->from.scale, &p->to); - else if(p->as == ATEXT) - sprint(str, " %A %D,%d,%D", - p->as, &p->from, p->from.scale, &p->to); + a = p->as; + s = p->scond; + strcpy(sc, extra[s & C_SCOND]); + if(s & C_SBIT) + strcat(sc, ".S"); + if(s & C_PBIT) + strcat(sc, ".P"); + if(s & C_WBIT) + strcat(sc, ".W"); + if(s & C_UBIT) /* ambiguous with FBIT */ + strcat(sc, ".U"); + if(a == AMOVM) { + if(p->from.type == D_CONST) + sprint(str, " %A%s %R,%D", a, sc, &p->from, &p->to); + else + if(p->to.type == D_CONST) + sprint(str, " %A%s %D,%R", a, sc, &p->from, &p->to); + else + sprint(str, " %A%s %D,%D", a, sc, &p->from, &p->to); + } else + if(a == ADATA) + sprint(str, " %A %D/%d,%D", a, &p->from, p->reg, &p->to); else - sprint(str, " %A %D,%D", - p->as, &p->from, &p->to); + if(p->as == ATEXT) + sprint(str, " %A %D,%d,%D", a, &p->from, p->reg, &p->to); + else + if(p->reg == NREG) + sprint(str, " %A%s %D,%D", a, sc, &p->from, &p->to); + else + if(p->from.type != D_FREG) + sprint(str, " %A%s %D,R%d,%D", a, sc, &p->from, p->reg, &p->to); + else + sprint(str, " %A%s %D,F%d,%D", a, sc, &p->from, p->reg, &p->to); return fmtstrcpy(fp, str); } int Aconv(Fmt *fp) { - int i; + char *s; + int a; - i = va_arg(fp->args, int); - return fmtstrcpy(fp, anames[i]); + a = va_arg(fp->args, int); + s = "???"; + if(a >= AXXX && a < ALAST) + s = anames[a]; + return fmtstrcpy(fp, s); } int Dconv(Fmt *fp) { - char str[40], s[20]; + char str[STRINGSZ]; Adr *a; - int i; + char *op; + int v; a = va_arg(fp->args, Adr*); - i = a->type; - if(i >= D_INDIR) { - if(a->offset) - sprint(str, "%lld(%R)", a->offset, i-D_INDIR); - else - sprint(str, "(%R)", i-D_INDIR); - goto brk; - } - switch(i) { + switch(a->type) { default: - if(a->offset) - sprint(str, "$%lld,%R", a->offset, i); - else - sprint(str, "%R", i); + sprint(str, "GOK-type(%d)", a->type); break; case D_NONE: str[0] = 0; + if(a->name != D_NONE || a->reg != NREG || a->sym != S) + sprint(str, "%N(R%d)(NONE)", a, a->reg); + break; + + case D_CONST: + if(a->reg != NREG) + sprint(str, "$%N(R%d)", a, a->reg); + else + sprint(str, "$%N", a); + break; + + case D_CONST2: + sprint(str, "$%d-%d", a->offset, a->offset2); + break; + + case D_SHIFT: + v = a->offset; + op = "<<>>->@>" + (((v>>5) & 3) << 1); + if(v & (1<<4)) + sprint(str, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15); + else + sprint(str, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31); + if(a->reg != NREG) + sprint(str+strlen(str), "(R%d)", a->reg); + break; + + case D_OREG: + if(a->reg != NREG) + sprint(str, "%N(R%d)", a, a->reg); + else + sprint(str, "%N", a); + break; + + case D_REG: + sprint(str, "R%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(R%d)(REG)", a, a->reg); + break; + + case D_FREG: + sprint(str, "F%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(R%d)(REG)", a, a->reg); + break; + + case D_PSR: + sprint(str, "PSR"); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(PSR)(REG)", a); break; case D_BRANCH: - sprint(str, "%lld(PC)", a->offset-pc); - break; - - case D_EXTERN: - sprint(str, "%s+%lld(SB)", a->sym->name, a->offset); - break; - - case D_STATIC: - sprint(str, "%s<>+%lld(SB)", a->sym->name, - a->offset); - break; - - case D_AUTO: - sprint(str, "%s+%lld(SP)", a->sym->name, a->offset); - break; - - case D_PARAM: - if(a->sym) - sprint(str, "%s+%lld(FP)", a->sym->name, a->offset); - else - sprint(str, "%lld(FP)", a->offset); - break; - - case D_CONST: - sprint(str, "$%lld", a->offset); + sprint(str, "%d(PC)", a->offset-pc); break; case D_FCONST: - sprint(str, "$(%.17e)", a->dval); + sprint(str, "$%.17e", a->dval); break; case D_SCONST: sprint(str, "$\"%S\"", a->sval); break; - - case D_ADDR: - a->type = a->index; - a->index = D_NONE; - sprint(str, "$%D", a); - a->index = a->type; - a->type = D_ADDR; - goto conv; } -brk: - if(a->index != D_NONE) { - sprint(s, "(%R*%d)", (int)a->index, (int)a->scale); - strcat(str, s); - } -conv: return fmtstrcpy(fp, str); } -char* regstr[] = -{ - "AL", /* [D_AL] */ - "CL", - "DL", - "BL", - "SPB", - "BPB", - "SIB", - "DIB", - "R8B", - "R9B", - "R10B", - "R11B", - "R12B", - "R13B", - "R14B", - "R15B", - - "AX", /* [D_AX] */ - "CX", - "DX", - "BX", - "SP", - "BP", - "SI", - "DI", - "R8", - "R9", - "R10", - "R11", - "R12", - "R13", - "R14", - "R15", - - "AH", - "CH", - "DH", - "BH", - - "F0", /* [D_F0] */ - "F1", - "F2", - "F3", - "F4", - "F5", - "F6", - "F7", - - "M0", - "M1", - "M2", - "M3", - "M4", - "M5", - "M6", - "M7", - - "X0", - "X1", - "X2", - "X3", - "X4", - "X5", - "X6", - "X7", - "X8", - "X9", - "X10", - "X11", - "X12", - "X13", - "X14", - "X15", - - "CS", /* [D_CS] */ - "SS", - "DS", - "ES", - "FS", - "GS", - - "GDTR", /* [D_GDTR] */ - "IDTR", /* [D_IDTR] */ - "LDTR", /* [D_LDTR] */ - "MSW", /* [D_MSW] */ - "TASK", /* [D_TASK] */ - - "CR0", /* [D_CR] */ - "CR1", - "CR2", - "CR3", - "CR4", - "CR5", - "CR6", - "CR7", - "CR8", - "CR9", - "CR10", - "CR11", - "CR12", - "CR13", - "CR14", - "CR15", - - "DR0", /* [D_DR] */ - "DR1", - "DR2", - "DR3", - "DR4", - "DR5", - "DR6", - "DR7", - - "TR0", /* [D_TR] */ - "TR1", - "TR2", - "TR3", - "TR4", - "TR5", - "TR6", - "TR7", - - "NONE", /* [D_NONE] */ -}; - int Rconv(Fmt *fp) { - char str[20]; - int r; + char str[STRINGSZ]; + Adr *a; + int i, v; - r = va_arg(fp->args, int); - if(r >= D_AL && r <= D_NONE) - sprint(str, "%s", regstr[r-D_AL]); - else - sprint(str, "gok(%d)", r); - + a = va_arg(fp->args, Adr*); + sprint(str, "GOK-reglist"); + switch(a->type) { + case D_CONST: + case D_CONST2: + if(a->reg != NREG) + break; + if(a->sym != S) + break; + v = a->offset; + strcpy(str, ""); + for(i=0; iargs, char*); p = str; - for(i=0; i= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || - c >= '0' && c <= '9') { + c >= '0' && c <= '9' || + c == ' ' || c == '%') { *p++ = c; continue; } *p++ = '\\'; switch(c) { - default: - if(c < 040 || c >= 0177) - break; /* not portable */ - p[-1] = c; - continue; case 0: *p++ = 'z'; continue; @@ -327,6 +282,12 @@ case '\t': *p++ = 't'; continue; + case '\r': + *p++ = 'r'; + continue; + case '\f': + *p++ = 'f'; + continue; } *p++ = (c>>6) + '0'; *p++ = ((c>>3) & 7) + '0'; @@ -335,3 +296,45 @@ *p = 0; return fmtstrcpy(fp, str); } + +int +Nconv(Fmt *fp) +{ + char str[STRINGSZ]; + Adr *a; + Sym *s; + + a = va_arg(fp->args, Adr*); + s = a->sym; + if(s == S) { + sprint(str, "%d", a->offset); + goto out; + } + switch(a->name) { + default: + sprint(str, "GOK-name(%d)", a->name); + break; + + case D_NONE: + sprint(str, "%d", a->offset); + break; + + case D_EXTERN: + sprint(str, "%s+%d(SB)", s->name, a->offset); + break; + + case D_STATIC: + sprint(str, "%s<>+%d(SB)", s->name, a->offset); + break; + + case D_AUTO: + sprint(str, "%s-%d(SP)", s->name, -a->offset); + break; + + case D_PARAM: + sprint(str, "%s+%d(FP)", s->name, a->offset); + break; + } +out: + return fmtstrcpy(fp, str); +} diff -r d8d00747375b sys/src/cmd/6c/machcap.c --- a/sys/src/cmd/6c/machcap.c Thu Sep 29 03:00:00 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ -#include "gc.h" - -int -machcap(Node *n) -{ - - if(n == Z) - return 1; /* test */ - - switch(n->op) { - case OMUL: - case OLMUL: - case OASMUL: - case OASLMUL: - if(typechl[n->type->etype]) - return 1; - if(typev[n->type->etype]) { - return 1; - } - break; - - case OCOM: - case ONEG: - case OADD: - case OAND: - case OOR: - case OSUB: - case OXOR: - case OASHL: - case OLSHR: - case OASHR: - if(typechlv[n->left->type->etype]) - return 1; - break; - - case OCAST: - return 1; - - case OCOND: - case OCOMMA: - case OLIST: - case OANDAND: - case OOROR: - case ONOT: - return 1; - - case OASADD: - case OASSUB: - case OASAND: - case OASOR: - case OASXOR: - return 1; - - case OASASHL: - case OASASHR: - case OASLSHR: - return 1; - - case OPOSTINC: - case OPOSTDEC: - case OPREINC: - case OPREDEC: - return 1; - - case OEQ: - case ONE: - case OLE: - case OGT: - case OLT: - case OGE: - case OHI: - case OHS: - case OLO: - case OLS: - return 1; - } - return 0; -} diff -r d8d00747375b sys/src/cmd/6c/mkenam --- a/sys/src/cmd/6c/mkenam Thu Sep 29 03:00:00 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -ed - ../6c/6.out.h <<'!' -v/^ A/d -,s/^ A/ "/ -g/ .*$/s/// -,s/,*$/",/ -1i -char* anames[] = -{ -. -$a -}; -. -w enam.c -Q -! diff -r d8d00747375b sys/src/cmd/6c/mkfile --- a/sys/src/cmd/6c/mkfile Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/6c/mkfile Mon Nov 14 17:35:25 2011 +0100 @@ -12,13 +12,11 @@ peep.$O\ pgen.$O\ pswt.$O\ - machcap.$O\ - div.$O\ mul.$O\ HFILES=\ gc.h\ - 6.out.h\ + ../6l/6.out.h\ ../cc/cc.h\ LIB=../cc/cc.a$O @@ -34,5 +32,7 @@ %.$O: ../cc/%.c $CC $CFLAGS ../cc/$stem.c -bound.$O: bound.h +enam.c: ../6l/6.out.h + ape/psh ../6l/mkenam +CLEANFILES=enam.c diff -r d8d00747375b sys/src/cmd/6c/mul.c --- a/sys/src/cmd/6c/mul.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/6c/mul.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,428 +1,640 @@ +// Inferno utils/5c/mul.c +// http://code.google.com/p/inferno-os/source/browse/utils/5c/mul.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 "gc.h" -typedef struct Malg Malg; -typedef struct Mparam Mparam; +/* + * code sequences for multiply by constant. + * [a-l][0-3] + * lsl $(A-'a'),r0,r1 + * [+][0-7] + * add r0,r1,r2 + * [-][0-7] + * sub r0,r1,r2 + */ -struct Malg +static int maxmulops = 3; /* max # of ops to replace mul with */ +static int multabp; +static int32 mulval; +static char* mulcp; +static int32 valmax; +static int shmax; + +static int docode(char *hp, char *cp, int r0, int r1); +static int gen1(int len); +static int gen2(int len, int32 r1); +static int gen3(int len, int32 r0, int32 r1, int flag); +enum { - char vals[10]; + SR1 = 1<<0, /* r1 has been shifted */ + SR0 = 1<<1, /* r0 has been shifted */ + UR1 = 1<<2, /* r1 has not been used */ + UR0 = 1<<3, /* r0 has not been used */ }; -struct Mparam +Multab* +mulcon0(int32 v) { - ulong value; - char alg; - char neg; - char shift; - char arg; - char off; -}; + int a1, a2, g; + Multab *m, *m1; + char hint[10]; -static Mparam multab[32]; -static int mulptr; + if(v < 0) + v = -v; -static Malg malgs[] = -{ - {0, 100}, - {-1, 1, 100}, - {-9, -5, -3, 3, 5, 9, 100}, - {6, 10, 12, 18, 20, 24, 36, 40, 72, 100}, - {-8, -4, -2, 2, 4, 8, 100}, -}; + /* + * look in cache + */ + m = multab; + for(g=0; gval == v) { + if(m->code[0] == 0) + return 0; + return m; + } + m++; + } -/* - * return position of lowest 1 - */ -int -lowbit(ulong v) -{ - int s, i; - ulong m; + /* + * select a spot in cache to overwrite + */ + multabp++; + if(multabp < 0 || multabp >= nelem(multab)) + multabp = 0; + m = multab+multabp; + m->val = v; + mulval = v; - s = 0; - m = 0xFFFFFFFFUL; - for(i = 16; i > 0; i >>= 1) { - m >>= i; - if((v & m) == 0) { - v >>= i; - s += i; + /* + * look in execption hint table + */ + a1 = 0; + a2 = hintabsize; + for(;;) { + if(a1 >= a2) + goto no; + g = (a2 + a1)/2; + if(v < hintab[g].val) { + a2 = g; + continue; + } + if(v > hintab[g].val) { + a1 = g+1; + continue; + } + break; + } + + if(docode(hintab[g].hint, m->code, 1, 0)) + return m; + print("multiply table failure %d\n", v); + m->code[0] = 0; + return 0; + +no: + /* + * try to search + */ + hint[0] = 0; + for(g=1; g<=maxmulops; g++) { + if(g >= maxmulops && v >= 65535) + break; + mulcp = hint+g; + *mulcp = 0; + if(gen1(g)) { + if(docode(hint, m->code, 1, 0)) + return m; + print("multiply table failure %d\n", v); + break; } } - return s; + + /* + * try a recur followed by a shift + */ + g = 0; + while(!(v & 1)) { + g++; + v >>= 1; + } + if(g) { + m1 = mulcon0(v); + if(m1) { + strcpy(m->code, m1->code); + sprint(strchr(m->code, 0), "%c0", g+'a'); + return m; + } + } + m->code[0] = 0; + return 0; } -void -genmuladd(Node *d, Node *s, int m, Node *a) +static int +docode(char *hp, char *cp, int r0, int r1) { - Node nod; + int c, i; - nod.op = OINDEX; - nod.left = a; - nod.right = s; - nod.scale = m; - nod.type = types[TIND]; - nod.xoffset = 0; - xcom(&nod); - gopcode(OADDR, d->type, &nod, d); + c = *hp++; + *cp = c; + cp += 2; + switch(c) { + default: + c -= 'a'; + if(c < 1 || c >= 30) + break; + for(i=0; i<4; i++) { + switch(i) { + case 0: + if(docode(hp, cp, r0< 0) - continue; - u = -u; + for(shmax=1; shmax<30; shmax++) { + valmax = 1<= mulval) + break; + } + if(mulval == 1) + return 1; + + len--; + for(i=1; i<=shmax; i++) + if(gen2(len, 1<= r1 || + r1 > valmax) + return 0; + + len--; + if(len == 0) + goto calcr0; + + if(!(flag & UR1)) { + f1 = UR1|SR1; + for(i=1; i<=shmax; i++) { + x = r0< valmax) + break; + if(gen3(len, r0, x, f1)) { + i += 'a'; + goto out; } - n = lowbit(u); - t = (ulong)u >> n; - switch(i) { - case 0: - if(t == 1) { - c = s + 1; - q = 0; - break; + } + } + + if(!(flag & UR0)) { + f1 = UR1|SR1; + for(i=1; i<=shmax; i++) { + x = r1< valmax) + break; + if(gen3(len, r1, x, f1)) { + i += 'a'; + goto out; + } + } + } + + if(!(flag & SR1)) { + f1 = UR1|SR1|(flag&UR0); + for(i=1; i<=shmax; i++) { + x = r1< valmax) + break; + if(gen3(len, r0, x, f1)) { + i += 'a'; + goto out; + } + } + } + + if(!(flag & SR0)) { + f1 = UR0|SR0|(flag&(SR1|UR1)); + + f2 = UR1|SR1; + if(flag & UR1) + f2 |= UR0; + if(flag & SR1) + f2 |= SR0; + + for(i=1; i<=shmax; i++) { + x = r0< valmax) + break; + if(x > r1) { + if(gen3(len, r1, x, f2)) { + i += 'a'; + goto out; } - switch(t) { - case 3: - case 5: - case 9: - c = s + 1; - if(n) - c++; - q = 0; - break; + } else + if(gen3(len, x, r1, f1)) { + i += 'a'; + goto out; } - if(s) - break; - switch(t) { - case 15: - case 25: - case 27: - case 45: - case 81: - c = 2; - if(n) - c++; - q = 1; - break; - } - break; - case 1: - if(t == 1) { - c = 3; - q = 3; - break; - } - switch(t) { - case 3: - case 5: - case 9: - c = 3; - q = 2; - break; - } - break; - case 2: - if(t == 1) { - c = 3; - q = 2; - break; - } - break; - case 3: - if(s) - break; - if(t == 1) { - c = 3; - q = 1; - break; - } - break; - case 4: - if(t == 1) { - c = 3; - q = 0; - break; + } + } + + x = r1+r0; + if(gen3(len, r0, x, UR1)) { + i = '+'; + goto out; + } + + if(gen3(len, r1, x, UR1)) { + i = '+'; + goto out; + } + + x = r1-r0; + if(gen3(len, x, r1, UR0)) { + i = '-'; + goto out; + } + + if(x > r0) { + if(gen3(len, r0, x, UR1)) { + i = '-'; + goto out; + } + } else + if(gen3(len, x, r0, UR0)) { + i = '-'; + goto out; + } + + return 0; + +calcr0: + f1 = flag & (UR0|UR1); + if(f1 == UR1) { + for(i=1; i<=shmax; i++) { + x = r1<= mulval) { + if(x == mulval) { + i += 'a'; + goto out; } break; } - if(c < bc || (c == bc && q > bq)) { - bc = c; - bi = i; - bn = n; - bo = o; - bq = q; - bs = s; - bt = t; - } } } - mp->value = m; - if(bc <= 3) { - mp->alg = bi; - mp->shift = bn; - mp->off = bo; - mp->neg = bs; - mp->arg = bt; + + if(mulval == r1+r0) { + i = '+'; + goto out; } - else - mp->alg = -1; -} - -int -m0(int a) -{ - switch(a) { - case -2: - case 2: - return 2; - case -3: - case 3: - return 2; - case -4: - case 4: - return 4; - case -5: - case 5: - return 4; - case 6: - return 2; - case -8: - case 8: - return 8; - case -9: - case 9: - return 8; - case 10: - return 4; - case 12: - return 2; - case 15: - return 2; - case 18: - return 8; - case 20: - return 4; - case 24: - return 2; - case 25: - return 4; - case 27: - return 2; - case 36: - return 8; - case 40: - return 4; - case 45: - return 4; - case 72: - return 8; - case 81: - return 8; - } - diag(Z, "bad m0"); - return 0; -} - -int -m1(int a) -{ - switch(a) { - case 15: - return 4; - case 25: - return 4; - case 27: - return 8; - case 45: - return 8; - case 81: - return 8; - } - diag(Z, "bad m1"); - return 0; -} - -int -m2(int a) -{ - switch(a) { - case 6: - return 2; - case 10: - return 2; - case 12: - return 4; - case 18: - return 2; - case 20: - return 4; - case 24: - return 8; - case 36: - return 4; - case 40: - return 8; - case 72: - return 8; - } - diag(Z, "bad m2"); - return 0; -} - -void -shiftit(Type *t, Node *s, Node *d) -{ - long c; - - c = (long)s->vconst & 31; - switch(c) { - case 0: - break; - case 1: - gopcode(OADD, t, d, d); - break; - default: - gopcode(OASHL, t, s, d); - } -} - -static int -mulgen1(ulong v, Node *n) -{ - int i, o; - Mparam *p; - Node nod, nods; - - for(i = 0; i < nelem(multab); i++) { - p = &multab[i]; - if(p->value == v) - goto found; + if(mulval == r1-r0) { + i = '-'; + goto out; } - p = &multab[mulptr]; - if(++mulptr == nelem(multab)) - mulptr = 0; + return 0; - mulparam(v, p); - -found: -// print("v=%.lx a=%d n=%d s=%d g=%d o=%d \n", p->value, p->alg, p->neg, p->shift, p->arg, p->off); - if(p->alg < 0) - return 0; - - nods = *nodconst(p->shift); - - o = OADD; - if(p->alg > 0) { - regalloc(&nod, n, Z); - if(p->off < 0) - o = OSUB; - } - - switch(p->alg) { - case 0: - switch(p->arg) { - case 1: - shiftit(n->type, &nods, n); - break; - case 15: - case 25: - case 27: - case 45: - case 81: - genmuladd(n, n, m1(p->arg), n); - /* fall thru */ - case 3: - case 5: - case 9: - genmuladd(n, n, m0(p->arg), n); - shiftit(n->type, &nods, n); - break; - default: - goto bad; - } - if(p->neg == 1) - gins(ANEGL, Z, n); - break; - case 1: - switch(p->arg) { - case 1: - gmove(n, &nod); - shiftit(n->type, &nods, &nod); - break; - case 3: - case 5: - case 9: - genmuladd(&nod, n, m0(p->arg), n); - shiftit(n->type, &nods, &nod); - break; - default: - goto bad; - } - if(p->neg) - gopcode(o, n->type, &nod, n); - else { - gopcode(o, n->type, n, &nod); - gmove(&nod, n); - } - break; - case 2: - genmuladd(&nod, n, m0(p->off), n); - shiftit(n->type, &nods, n); - goto comop; - case 3: - genmuladd(&nod, n, m0(p->off), n); - shiftit(n->type, &nods, n); - genmuladd(n, &nod, m2(p->off), n); - break; - case 4: - genmuladd(&nod, n, m0(p->off), nodconst(0)); - shiftit(n->type, &nods, n); - goto comop; - default: - diag(Z, "bad mul alg"); - break; - comop: - if(p->neg) { - gopcode(o, n->type, n, &nod); - gmove(&nod, n); - } - else - gopcode(o, n->type, &nod, n); - } - - if(p->alg > 0) - regfree(&nod); - - return 1; - -bad: - diag(Z, "mulgen botch"); +out: + *--mulcp = i; return 1; } -void -mulgen(Type *t, Node *r, Node *n) +/* + * hint table has numbers that + * the search algorithm fails on. + * <1000: + * all numbers + * <5000: + * ÷ by 5 + * <10000: + * ÷ by 50 + * <65536: + * ÷ by 250 + */ +Hintab hintab[] = { - if(!mulgen1(r->vconst, n)) - gopcode(OMUL, t, r, n); -} + 683, "b++d+e+", + 687, "b+e++e-", + 691, "b++d+e+", + 731, "b++d+e+", + 811, "b++d+i+", + 821, "b++e+e+", + 843, "b+d++e+", + 851, "b+f-+e-", + 853, "b++e+e+", + 877, "c++++g-", + 933, "b+c++g-", + 981, "c-+e-d+", + 1375, "b+c+b+h-", + 1675, "d+b++h+", + 2425, "c++f-e+", + 2675, "c+d++f-", + 2750, "b+d-b+h-", + 2775, "c-+g-e-", + 3125, "b++e+g+", + 3275, "b+c+g+e+", + 3350, "c++++i+", + 3475, "c-+e-f-", + 3525, "c-+d+g-", + 3625, "c-+e-j+", + 3675, "b+d+d+e+", + 3725, "b+d-+h+", + 3925, "b+d+f-d-", + 4275, "b+g++e+", + 4325, "b+h-+d+", + 4425, "b+b+g-j-", + 4525, "b+d-d+f+", + 4675, "c++d-g+", + 4775, "b+d+b+g-", + 4825, "c+c-+i-", + 4850, "c++++i-", + 4925, "b++e-g-", + 4975, "c+f++e-", + 5500, "b+g-c+d+", + 6700, "d+b++i+", + 9700, "d++++j-", + 11000, "b+f-c-h-", + 11750, "b+d+g+j-", + 12500, "b+c+e-k+", + 13250, "b+d+e-f+", + 13750, "b+h-c-d+", + 14250, "b+g-c+e-", + 14500, "c+f+j-d-", + 14750, "d-g--f+", + 16750, "b+e-d-n+", + 17750, "c+h-b+e+", + 18250, "d+b+h-d+", + 18750, "b+g-++f+", + 19250, "b+e+b+h+", + 19750, "b++h--f-", + 20250, "b+e-l-c+", + 20750, "c++bi+e-", + 21250, "b+i+l+c+", + 22000, "b+e+d-g-", + 22250, "b+d-h+k-", + 22750, "b+d-e-g+", + 23250, "b+c+h+e-", + 23500, "b+g-c-g-", + 23750, "b+g-b+h-", + 24250, "c++g+m-", + 24750, "b+e+e+j-", + 25000, "b++dh+g+", + 25250, "b+e+d-g-", + 25750, "b+e+b+j+", + 26250, "b+h+c+e+", + 26500, "b+h+c+g+", + 26750, "b+d+e+g-", + 27250, "b+e+e+f+", + 27500, "c-i-c-d+", + 27750, "b+bd++j+", + 28250, "d-d-++i-", + 28500, "c+c-h-e-", + 29000, "b+g-d-f+", + 29500, "c+h+++e-", + 29750, "b+g+f-c+", + 30250, "b+f-g-c+", + 33500, "c-f-d-n+", + 33750, "b+d-b+j-", + 34250, "c+e+++i+", + 35250, "e+b+d+k+", + 35500, "c+e+d-g-", + 35750, "c+i-++e+", + 36250, "b+bh-d+e+", + 36500, "c+c-h-e-", + 36750, "d+e--i+", + 37250, "b+g+g+b+", + 37500, "b+h-b+f+", + 37750, "c+be++j-", + 38500, "b+e+b+i+", + 38750, "d+i-b+d+", + 39250, "b+g-l-+d+", + 39500, "b+g-c+g-", + 39750, "b+bh-c+f-", + 40250, "b+bf+d+g-", + 40500, "b+g-c+g+", + 40750, "c+b+i-e+", + 41250, "d++bf+h+", + 41500, "b+j+c+d-", + 41750, "c+f+b+h-", + 42500, "c+h++g+", + 42750, "b+g+d-f-", + 43250, "b+l-e+d-", + 43750, "c+bd+h+f-", + 44000, "b+f+g-d-", + 44250, "b+d-g--f+", + 44500, "c+e+c+h+", + 44750, "b+e+d-h-", + 45250, "b++g+j-g+", + 45500, "c+d+e-g+", + 45750, "b+d-h-e-", + 46250, "c+bd++j+", + 46500, "b+d-c-j-", + 46750, "e-e-b+g-", + 47000, "b+c+d-j-", + 47250, "b+e+e-g-", + 47500, "b+g-c-h-", + 47750, "b+f-c+h-", + 48250, "d--h+n-", + 48500, "b+c-g+m-", + 48750, "b+e+e-g+", + 49500, "c-f+e+j-", + 49750, "c+c+g++f-", + 50000, "b+e+e+k+", + 50250, "b++i++g+", + 50500, "c+g+f-i+", + 50750, "b+e+d+k-", + 51500, "b+i+c-f+", + 51750, "b+bd+g-e-", + 52250, "b+d+g-j+", + 52500, "c+c+f+g+", + 52750, "b+c+e+i+", + 53000, "b+i+c+g+", + 53500, "c+g+g-n+", + 53750, "b+j+d-c+", + 54250, "b+d-g-j-", + 54500, "c-f+e+f+", + 54750, "b+f-+c+g+", + 55000, "b+g-d-g-", + 55250, "b+e+e+g+", + 55500, "b+cd++j+", + 55750, "b+bh-d-f-", + 56250, "c+d-b+j-", + 56500, "c+d+c+i+", + 56750, "b+e+d++h-", + 57000, "b+d+g-f+", + 57250, "b+f-m+d-", + 57750, "b+i+c+e-", + 58000, "b+e+d+h+", + 58250, "c+b+g+g+", + 58750, "d-e-j--e+", + 59000, "d-i-+e+", + 59250, "e--h-m+", + 59500, "c+c-h+f-", + 59750, "b+bh-e+i-", + 60250, "b+bh-e-e-", + 60500, "c+c-g-g-", + 60750, "b+e-l-e-", + 61250, "b+g-g-c+", + 61750, "b+g-c+g+", + 62250, "f--+c-i-", + 62750, "e+f--+g+", + 64750, "b+f+d+p-", +}; +int hintabsize = nelem(hintab); diff -r d8d00747375b sys/src/cmd/6c/peep.c --- a/sys/src/cmd/6c/peep.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/6c/peep.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,52 +1,37 @@ +// Inferno utils/5c/peep.c +// http://code.google.com/p/inferno-os/source/browse/utils/5c/peep.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 "gc.h" -static int -needc(Prog *p) -{ - while(p != P) { - switch(p->as) { - case AADCL: - case AADCQ: - case ASBBL: - case ASBBQ: - case ARCRL: - case ARCRQ: - return 1; - case AADDL: - case AADDQ: - case ASUBL: - case ASUBQ: - case AJMP: - case ARET: - case ACALL: - return 0; - default: - if(p->to.type == D_BRANCH) - return 0; - } - p = p->link; - } - return 0; -} - -static Reg* -rnops(Reg *r) -{ - Prog *p; - Reg *r1; - - if(r != R) - for(;;){ - p = r->prog; - if(p->as != ANOP || p->from.type != D_NONE || p->to.type != D_NONE) - break; - r1 = uniqs(r); - if(r1 == R) - break; - r = r1; - } - return r; -} +int xtramodes(Reg*, Adr*); void peep(void) @@ -54,10 +39,9 @@ Reg *r, *r1, *r2; Prog *p, *p1; int t; - - /* - * complete R structure - */ +/* + * complete R structure + */ t = 0; for(r=firstr; r!=R; r=r1) { r1 = r->link; @@ -88,20 +72,25 @@ } } - pc = 0; /* speculating it won't kill */ - loop1: - t = 0; for(r=firstr; r!=R; r=r->link) { p = r->prog; - switch(p->as) { - case AMOVL: - case AMOVQ: - case AMOVSS: - case AMOVSD: - if(regtyp(&p->to)) - if(regtyp(&p->from)) { + if(p->as == ASLL || p->as == ASRL || p->as == ASRA) { + /* + * elide shift into D_SHIFT operand of subsequent instruction + */ + if(shiftprop(r)) { + excise(r); + t++; + } + } + if(p->as == AMOVW || p->as == AMOVF || p->as == AMOVD) + if(regtyp(&p->to)) { + if(p->from.type == D_CONST) + constprop(&p->from, &p->to, r->s1); + else if(regtyp(&p->from)) + if(p->from.type == p->to.type) { if(copyprop(r)) { excise(r); t++; @@ -111,95 +100,136 @@ t++; } } - break; - - case AMOVBLZX: - case AMOVWLZX: - case AMOVBLSX: - case AMOVWLSX: - if(regtyp(&p->to)) { - r1 = rnops(uniqs(r)); - if(r1 != R) { - p1 = r1->prog; - if(p->as == p1->as && p->to.type == p1->from.type){ - p1->as = AMOVL; - t++; - } - } - } - break; - - case AMOVBQSX: - case AMOVBQZX: - case AMOVWQSX: - case AMOVWQZX: - case AMOVLQSX: - case AMOVLQZX: - if(regtyp(&p->to)) { - r1 = rnops(uniqs(r)); - if(r1 != R) { - p1 = r1->prog; - if(p->as == p1->as && p->to.type == p1->from.type){ - p1->as = AMOVQ; - t++; - } - } - } - break; - - case AADDL: - case AADDQ: - case AADDW: - if(p->from.type != D_CONST || needc(p->link)) - break; - if(p->from.offset == -1){ - if(p->as == AADDQ) - p->as = ADECQ; - else if(p->as == AADDL) - p->as = ADECL; - else - p->as = ADECW; - p->from = zprog.from; - } - else if(p->from.offset == 1){ - if(p->as == AADDQ) - p->as = AINCQ; - else if(p->as == AADDL) - p->as = AINCL; - else - p->as = AINCW; - p->from = zprog.from; - } - break; - - case ASUBL: - case ASUBQ: - case ASUBW: - if(p->from.type != D_CONST || needc(p->link)) - break; - if(p->from.offset == -1) { - if(p->as == ASUBQ) - p->as = AINCQ; - else if(p->as == ASUBL) - p->as = AINCL; - else - p->as = AINCW; - p->from = zprog.from; - } - else if(p->from.offset == 1){ - if(p->as == ASUBQ) - p->as = ADECQ; - else if(p->as == ASUBL) - p->as = ADECL; - else - p->as = ADECW; - p->from = zprog.from; - } - break; } } if(t) goto loop1; + /* + * look for MOVB x,R; MOVB R,R + */ + for(r=firstr; r!=R; r=r->link) { + p = r->prog; + switch(p->as) { + default: + continue; + case AEOR: + /* + * EOR -1,x,y => MVN x,y + */ + if(p->from.type == D_CONST && p->from.offset == -1) { + p->as = AMVN; + p->from.type = D_REG; + if(p->reg != NREG) + p->from.reg = p->reg; + else + p->from.reg = p->to.reg; + p->reg = NREG; + } + continue; + case AMOVH: + case AMOVHU: + case AMOVB: + case AMOVBU: + if(p->to.type != D_REG) + continue; + break; + } + r1 = r->link; + if(r1 == R) + continue; + p1 = r1->prog; + if(p1->as != p->as) + continue; + if(p1->from.type != D_REG || p1->from.reg != p->to.reg) + continue; + if(p1->to.type != D_REG || p1->to.reg != p->to.reg) + continue; + excise(r1); + } + + for(r=firstr; r!=R; r=r->link) { + p = r->prog; + switch(p->as) { + case AMOVW: + case AMOVB: + case AMOVBU: + if(p->from.type == D_OREG && p->from.offset == 0) + xtramodes(r, &p->from); + else if(p->to.type == D_OREG && p->to.offset == 0) + xtramodes(r, &p->to); + else + continue; + break; + case ACMP: + /* + * elide CMP $0,x if calculation of x can set condition codes + */ + if(p->from.type != D_CONST || p->from.offset != 0) + continue; + r2 = r->s1; + if(r2 == R) + continue; + t = r2->prog->as; + switch(t) { + default: + continue; + case ABEQ: + case ABNE: + case ABMI: + case ABPL: + break; + case ABGE: + t = ABPL; + break; + case ABLT: + t = ABMI; + break; + case ABHI: + t = ABNE; + break; + case ABLS: + t = ABEQ; + break; + } + r1 = r; + do + r1 = uniqp(r1); + while (r1 != R && r1->prog->as == ANOP); + if(r1 == R) + continue; + p1 = r1->prog; + if(p1->to.type != D_REG) + continue; + if(p1->to.reg != p->reg) + if(!(p1->as == AMOVW && p1->from.type == D_REG && p1->from.reg == p->reg)) + continue; + switch(p1->as) { + default: + continue; + case AMOVW: + if(p1->from.type != D_REG) + continue; + case AAND: + case AEOR: + case AORR: + case ABIC: + case AMVN: + case ASUB: + case ARSB: + case AADD: + case AADC: + case ASBC: + case ARSC: + break; + } + p1->scond |= C_SBIT; + r2->prog->as = t; + excise(r); + continue; + } + } + + predicate(); } void @@ -209,8 +239,10 @@ p = r->prog; p->as = ANOP; + p->scond = zprog.scond; p->from = zprog.from; p->to = zprog.to; + p->reg = zprog.reg; /**/ } Reg* @@ -248,12 +280,10 @@ int regtyp(Adr *a) { - int t; - t = a->type; - if(t >= D_AX && t <= D_R15) + if(a->type == D_REG) return 1; - if(t >= D_X0 && t <= D_X0+15) + if(a->type == D_FREG) return 1; return 0; } @@ -292,75 +322,63 @@ break; p = r->prog; switch(p->as) { - case ACALL: + case ABL: return 0; - case AIMULL: - case AIMULQ: - case AIMULW: - if(p->to.type != D_NONE) - break; + case ACMP: + case ACMN: + case AADD: + case ASUB: + case ARSB: + case ASLL: + case ASRL: + case ASRA: + case AORR: + case AAND: + case AEOR: + case AMUL: + case ADIV: + case ADIVU: - case ADIVB: - case ADIVL: - case ADIVQ: - case ADIVW: - case AIDIVB: - case AIDIVL: - case AIDIVQ: - case AIDIVW: - case AIMULB: - case AMULB: - case AMULL: - case AMULQ: - case AMULW: + case ACMPF: + case ACMPD: + case AADDD: + case AADDF: + case ASUBD: + case ASUBF: + case AMULD: + case AMULF: + case ADIVD: + case ADIVF: + if(p->to.type == v1->type) + if(p->to.reg == v1->reg) { + if(p->reg == NREG) + p->reg = p->to.reg; + goto gotit; + } + break; - case AROLB: - case AROLL: - case AROLQ: - case AROLW: - case ARORB: - case ARORL: - case ARORQ: - case ARORW: - case ASALB: - case ASALL: - case ASALQ: - case ASALW: - case ASARB: - case ASARL: - case ASARQ: - case ASARW: - case ASHLB: - case ASHLL: - case ASHLQ: - case ASHLW: - case ASHRB: - case ASHRL: - case ASHRQ: - case ASHRW: + case AMOVF: + case AMOVD: + case AMOVW: + if(p->to.type == v1->type) + if(p->to.reg == v1->reg) + goto gotit; + break; - case AREP: - case AREPN: - - case ACWD: - case ACDQ: - case ACQO: - - case AMOVSL: - case AMOVSQ: - return 0; - - case AMOVL: - case AMOVQ: - if(p->to.type == v1->type) - goto gotit; + case AMOVM: + t = 1<reg; + if((p->from.type == D_CONST && (p->from.offset&t)) || + (p->to.type == D_CONST && (p->to.offset&t))) + return 0; break; } if(copyau(&p->from, v2) || + copyau1(p, v2) || copyau(&p->to, v2)) break; if(copysub(&p->from, v1, v2, 0) || + copysub1(p, v1, v2, 0) || copysub(&p->to, v1, v2, 0)) break; } @@ -377,13 +395,14 @@ for(r=uniqs(r); r!=r0; r=uniqs(r)) { p = r->prog; copysub(&p->from, v1, v2, 1); + copysub1(p, v1, v2, 1); copysub(&p->to, v1, v2, 1); if(debug['P']) print("%P\n", r->prog); } - t = v1->type; - v1->type = v2->type; - v2->type = t; + t = v1->reg; + v1->reg = v2->reg; + v2->reg = t; if(debug['P']) print("%P last\n", r->prog); return 1; @@ -445,12 +464,12 @@ switch(t) { case 2: /* rar, cant split */ if(debug['P']) - print("; %D rar; return 0\n", v2); + print("; %Drar; return 0\n", v2); return 0; case 3: /* set */ if(debug['P']) - print("; %D set; return 1\n", v2); + print("; %Dset; return 1\n", v2); return 1; case 1: /* used, substitute */ @@ -459,9 +478,9 @@ if(!debug['P']) return 0; if(t == 4) - print("; %D used+set and f=%d; return 0\n", v2, f); + print("; %Dused+set and f=%d; return 0\n", v2, f); else - print("; %D used and f=%d; return 0\n", v2, f); + print("; %Dused and f=%d; return 0\n", v2, f); return 0; } if(copyu(p, v2, v1)) { @@ -470,10 +489,10 @@ return 0; } if(debug['P']) - print("; sub %D/%D", v2, v1); + print("; sub%D/%D", v2, v1); if(t == 4) { if(debug['P']) - print("; %D used+set; return 1\n", v2); + print("; %Dused+set; return 1\n", v2); return 1; } break; @@ -483,7 +502,7 @@ if(!f && (t == 2 || t == 3 || t == 4)) { f = 1; if(debug['P']) - print("; %D set and !f; f=%d", v1, f); + print("; %Dset and !f; f=%d", v1, f); } } if(debug['P']) @@ -496,6 +515,391 @@ } /* + * The idea is to remove redundant constants. + * $c1->v1 + * ($c1->v2 s/$c1/v1)* + * set v1 return + * The v1->v2 should be eliminated by copy propagation. + */ +void +constprop(Adr *c1, Adr *v1, Reg *r) +{ + Prog *p; + + if(debug['C']) + print("constprop %D->%D\n", c1, v1); + for(; r != R; r = r->s1) { + p = r->prog; + if(debug['C']) + print("%P", p); + if(uniqp(r) == R) { + if(debug['C']) + print("; merge; return\n"); + return; + } + if(p->as == AMOVW && copyas(&p->from, c1)) { + if(debug['C']) + print("; sub%D/%D", &p->from, v1); + p->from = *v1; + } else if(copyu(p, v1, A) > 1) { + if(debug['C']) + print("; %Dset; return\n", v1); + return; + } + if(debug['C']) + print("\n"); + if(r->s2) + constprop(c1, v1, r->s2); + } +} + +/* + * ASLL x,y,w + * .. (not use w, not set x y w) + * AXXX w,a,b (a != w) + * .. (not use w) + * (set w) + * ----------- changed to + * .. + * AXXX (x<prog; + if(p->to.type != D_REG) + FAIL("BOTCH: result not reg"); + n = p->to.reg; + a = zprog.from; + if(p->reg != NREG && p->reg != p->to.reg) { + a.type = D_REG; + a.reg = p->reg; + } + if(debug['H']) + print("shiftprop\n%P", p); + r1 = r; + for(;;) { + /* find first use of shift result; abort if shift operands or result are changed */ + r1 = uniqs(r1); + if(r1 == R) + FAIL("branch"); + if(uniqp(r1) == R) + FAIL("merge"); + p1 = r1->prog; + if(debug['H']) + print("\n%P", p1); + switch(copyu(p1, &p->to, A)) { + case 0: /* not used or set */ + if((p->from.type == D_REG && copyu(p1, &p->from, A) > 1) || + (a.type == D_REG && copyu(p1, &a, A) > 1)) + FAIL("args modified"); + continue; + case 3: /* set, not used */ + FAIL("BOTCH: noref"); + } + break; + } + /* check whether substitution can be done */ + switch(p1->as) { + default: + FAIL("non-dpi"); + case AAND: + case AEOR: + case AADD: + case AADC: + case AORR: + case ASUB: + case ARSB: + case ASBC: + case ARSC: + if(p1->reg == n || (p1->reg == NREG && p1->to.type == D_REG && p1->to.reg == n)) { + if(p1->from.type != D_REG) + FAIL("can't swap"); + p1->reg = p1->from.reg; + p1->from.reg = n; + switch(p1->as) { + case ASUB: + p1->as = ARSB; + break; + case ARSB: + p1->as = ASUB; + break; + case ASBC: + p1->as = ARSC; + break; + case ARSC: + p1->as = ASBC; + break; + } + if(debug['H']) + print("\t=>%P", p1); + } + case ABIC: + case ACMP: + case ACMN: + if(p1->reg == n) + FAIL("can't swap"); + if(p1->reg == NREG && p1->to.reg == n) + FAIL("shift result used twice"); + case AMVN: + if(p1->from.type == D_SHIFT) + FAIL("shift result used in shift"); + if(p1->from.type != D_REG || p1->from.reg != n) + FAIL("BOTCH: where is it used?"); + break; + } + /* check whether shift result is used subsequently */ + p2 = p1; + if(p1->to.reg != n) + for (;;) { + r1 = uniqs(r1); + if(r1 == R) + FAIL("inconclusive"); + p1 = r1->prog; + if(debug['H']) + print("\n%P", p1); + switch(copyu(p1, &p->to, A)) { + case 0: /* not used or set */ + continue; + case 3: /* set, not used */ + break; + default:/* used */ + FAIL("reused"); + } + break; + } + /* make the substitution */ + p2->from.type = D_SHIFT; + p2->from.reg = NREG; + o = p->reg; + if(o == NREG) + o = p->to.reg; + switch(p->from.type){ + case D_CONST: + o |= (p->from.offset&0x1f)<<7; + break; + case D_REG: + o |= (1<<4) | (p->from.reg<<8); + break; + } + switch(p->as){ + case ASLL: + o |= 0<<5; + break; + case ASRL: + o |= 1<<5; + break; + case ASRA: + o |= 2<<5; + break; + } + p2->from.offset = o; + if(debug['H']) + print("\t=>%P\tSUCCEED\n", p2); + return 1; +} + +Reg* +findpre(Reg *r, Adr *v) +{ + Reg *r1; + + for(r1=uniqp(r); r1!=R; r=r1,r1=uniqp(r)) { + if(uniqs(r1) != r) + return R; + switch(copyu(r1->prog, v, A)) { + case 1: /* used */ + case 2: /* read-alter-rewrite */ + return R; + case 3: /* set */ + case 4: /* set and used */ + return r1; + } + } + return R; +} + +Reg* +findinc(Reg *r, Reg *r2, Adr *v) +{ + Reg *r1; + Prog *p; + + + for(r1=uniqs(r); r1!=R && r1!=r2; r=r1,r1=uniqs(r)) { + if(uniqp(r1) != r) + return R; + switch(copyu(r1->prog, v, A)) { + case 0: /* not touched */ + continue; + case 4: /* set and used */ + p = r1->prog; + if(p->as == AADD) + if(p->from.type == D_CONST) + if(p->from.offset > -4096 && p->from.offset < 4096) + return r1; + default: + return R; + } + } + return R; +} + +int +nochange(Reg *r, Reg *r2, Prog *p) +{ + Adr a[3]; + int i, n; + + if(r == r2) + return 1; + n = 0; + if(p->reg != NREG && p->reg != p->to.reg) { + a[n].type = D_REG; + a[n++].reg = p->reg; + } + switch(p->from.type) { + case D_SHIFT: + a[n].type = D_REG; + a[n++].reg = p->from.offset&0xf; + case D_REG: + a[n].type = D_REG; + a[n++].reg = p->from.reg; + } + if(n == 0) + return 1; + for(; r!=R && r!=r2; r=uniqs(r)) { + p = r->prog; + for(i=0; i 1) + return 0; + } + return 1; +} + +int +findu1(Reg *r, Adr *v) +{ + for(; r != R; r = r->s1) { + if(r->active) + return 0; + r->active = 1; + switch(copyu(r->prog, v, A)) { + case 1: /* used */ + case 2: /* read-alter-rewrite */ + case 4: /* set and used */ + return 1; + case 3: /* set */ + return 0; + } + if(r->s2) + if (findu1(r->s2, v)) + return 1; + } + return 0; +} + +int +finduse(Reg *r, Adr *v) +{ + Reg *r1; + + for(r1=firstr; r1!=R; r1=r1->link) + r1->active = 0; + return findu1(r, v); +} + +int +xtramodes(Reg *r, Adr *a) +{ + Reg *r1, *r2, *r3; + Prog *p, *p1; + Adr v; + + p = r->prog; + if(debug['h'] && p->as == AMOVB && p->from.type == D_OREG) /* byte load */ + return 0; + v = *a; + v.type = D_REG; + r1 = findpre(r, &v); + if(r1 != R) { + p1 = r1->prog; + if(p1->to.type == D_REG && p1->to.reg == v.reg) + switch(p1->as) { + case AADD: + if(p1->from.type == D_REG || + (p1->from.type == D_SHIFT && (p1->from.offset&(1<<4)) == 0 && + (p->as != AMOVB || (a == &p->from && (p1->from.offset&~0xf) == 0))) || + (p1->from.type == D_CONST && + p1->from.offset > -4096 && p1->from.offset < 4096)) + if(nochange(uniqs(r1), r, p1)) { + if(a != &p->from || v.reg != p->to.reg) + if (finduse(r->s1, &v)) { + if(p1->reg == NREG || p1->reg == v.reg) + /* pre-indexing */ + p->scond |= C_WBIT; + else return 0; + } + switch (p1->from.type) { + case D_REG: + /* register offset */ + a->type = D_SHIFT; + a->offset = p1->from.reg; + break; + case D_SHIFT: + /* scaled register offset */ + a->type = D_SHIFT; + case D_CONST: + /* immediate offset */ + a->offset = p1->from.offset; + break; + } + if(p1->reg != NREG) + a->reg = p1->reg; + excise(r1); + return 1; + } + break; + case AMOVW: + if(p1->from.type == D_REG) + if((r2 = findinc(r1, r, &p1->from)) != R) { + for(r3=uniqs(r2); r3->prog->as==ANOP; r3=uniqs(r3)) + ; + if(r3 == r) { + /* post-indexing */ + p1 = r2->prog; + a->reg = p1->to.reg; + a->offset = p1->from.offset; + p->scond |= C_PBIT; + if(!finduse(r, &r1->prog->to)) + excise(r1); + excise(r2); + return 1; + } + } + break; + } + } + if(a != &p->from || a->reg != p->to.reg) + if((r1 = findinc(r, R, &v)) != R) { + /* post-indexing */ + p1 = r1->prog; + a->offset = p1->from.offset; + p->scond |= C_PBIT; + excise(r1); + return 1; + } + return 0; +} + +/* * return * 1 if v only used (and substitute), * 2 if read-alter-rewrite @@ -511,229 +915,170 @@ default: if(debug['P']) - print("unknown op %A\n", p->as); - /* SBBL; ADCL; FLD1; SAHF */ + print(" (?)"); return 2; + case AMOVM: + if(v->type != D_REG) + return 0; + if(p->from.type == D_CONST) { /* read reglist, read/rar */ + if(s != A) { + if(p->from.offset&(1<reg)) + return 1; + if(copysub(&p->to, v, s, 1)) + return 1; + return 0; + } + if(copyau(&p->to, v)) { + if(p->scond&C_WBIT) + return 2; + return 1; + } + if(p->from.offset&(1<reg)) + return 1; + } else { /* read/rar, write reglist */ + if(s != A) { + if(p->to.offset&(1<reg)) + return 1; + if(copysub(&p->from, v, s, 1)) + return 1; + return 0; + } + if(copyau(&p->from, v)) { + if(p->scond&C_WBIT) + return 2; + if(p->to.offset&(1<reg)) + return 4; + return 1; + } + if(p->to.offset&(1<reg)) + return 3; + } + return 0; - case ANEGB: - case ANEGW: - case ANEGL: - case ANEGQ: - case ANOTB: - case ANOTW: - case ANOTL: - case ANOTQ: - if(copyas(&p->to, v)) - return 2; - break; - - case ALEAL: /* lhs addr, rhs store */ - case ALEAQ: - if(copyas(&p->from, v)) - return 2; - - - case ANOP: /* rhs store */ - case AMOVL: - case AMOVQ: - case AMOVBLSX: - case AMOVBLZX: - case AMOVBQSX: - case AMOVBQZX: - case AMOVLQSX: - case AMOVLQZX: - case AMOVWLSX: - case AMOVWLZX: - case AMOVWQSX: - case AMOVWQZX: - - case AMOVSS: - case AMOVSD: - case ACVTSD2SL: - case ACVTSD2SQ: - case ACVTSD2SS: - case ACVTSL2SD: - case ACVTSL2SS: - case ACVTSQ2SD: - case ACVTSQ2SS: - case ACVTSS2SD: - case ACVTSS2SL: - case ACVTSS2SQ: - case ACVTTSD2SL: - case ACVTTSD2SQ: - case ACVTTSS2SL: - case ACVTTSS2SQ: + case ANOP: /* read, write */ + case AMOVW: + case AMOVF: + case AMOVD: + case AMOVH: + case AMOVHU: + case AMOVB: + case AMOVBU: + case AMOVDW: + case AMOVWD: + case AMOVFD: + case AMOVDF: + if(p->scond&(C_WBIT|C_PBIT)) + if(v->type == D_REG) { + if(p->from.type == D_OREG || p->from.type == D_SHIFT) { + if(p->from.reg == v->reg) + return 2; + } else { + if(p->to.reg == v->reg) + return 2; + } + } + if(s != A) { + if(copysub(&p->from, v, s, 1)) + return 1; + if(!copyas(&p->to, v)) + if(copysub(&p->to, v, s, 1)) + return 1; + return 0; + } if(copyas(&p->to, v)) { - if(s != A) - return copysub(&p->from, v, s, 1); if(copyau(&p->from, v)) return 4; return 3; } - goto caseread; - - case AROLB: - case AROLL: - case AROLQ: - case AROLW: - case ARORB: - case ARORL: - case ARORQ: - case ARORW: - case ASALB: - case ASALL: - case ASALQ: - case ASALW: - case ASARB: - case ASARL: - case ASARQ: - case ASARW: - case ASHLB: - case ASHLL: - case ASHLQ: - case ASHLW: - case ASHRB: - case ASHRL: - case ASHRQ: - case ASHRW: - if(copyas(&p->to, v)) - return 2; - if(copyas(&p->from, v)) - if(p->from.type == D_CX) - return 2; - goto caseread; - - case AADDB: /* rhs rar */ - case AADDL: - case AADDQ: - case AADDW: - case AANDB: - case AANDL: - case AANDQ: - case AANDW: - case ADECL: - case ADECQ: - case ADECW: - case AINCL: - case AINCQ: - case AINCW: - case ASUBB: - case ASUBL: - case ASUBQ: - case ASUBW: - case AORB: - case AORL: - case AORQ: - case AORW: - case AXORB: - case AXORL: - case AXORQ: - case AXORW: - case AMOVB: - case AMOVW: - - case AADDSD: - case AADDSS: - case ACMPSD: - case ACMPSS: - case ADIVSD: - case ADIVSS: - case AMAXSD: - case AMAXSS: - case AMINSD: - case AMINSS: - case AMULSD: - case AMULSS: - case ARCPSS: - case ARSQRTSS: - case ASQRTSD: - case ASQRTSS: - case ASUBSD: - case ASUBSS: - case AXORPD: - if(copyas(&p->to, v)) - return 2; - goto caseread; - - case ACMPL: /* read only */ - case ACMPW: - case ACMPB: - case ACMPQ: - - case ACOMISD: - case ACOMISS: - case AUCOMISD: - case AUCOMISS: - caseread: - if(s != A) { - if(copysub(&p->from, v, s, 1)) - return 1; - return copysub(&p->to, v, s, 1); - } if(copyau(&p->from, v)) return 1; if(copyau(&p->to, v)) return 1; - break; + return 0; - case AJGE: /* no reference */ - case AJNE: - case AJLE: - case AJEQ: - case AJHI: - case AJLS: - case AJMI: - case AJPL: - case AJGT: - case AJLT: - case AJCC: - case AJCS: - case AADJSP: - case AWAIT: - case ACLD: - break; + case AADD: /* read, read, write */ + case ASUB: + case ARSB: + case ASLL: + case ASRL: + case ASRA: + case AORR: + case AAND: + case AEOR: + case AMUL: + case ADIV: + case ADIVU: + case AADDF: + case AADDD: + case ASUBF: + case ASUBD: + case AMULF: + case AMULD: + case ADIVF: + case ADIVD: - case AIMULL: - case AIMULQ: - case AIMULW: - if(p->to.type != D_NONE) { - if(copyas(&p->to, v)) - return 2; - goto caseread; + case ACMPF: + case ACMPD: + case ACMP: + case ACMN: + case ACASE: + if(s != A) { + if(copysub(&p->from, v, s, 1)) + return 1; + if(copysub1(p, v, s, 1)) + return 1; + if(!copyas(&p->to, v)) + if(copysub(&p->to, v, s, 1)) + return 1; + return 0; } + if(copyas(&p->to, v)) { + if(p->reg == NREG) + p->reg = p->to.reg; + if(copyau(&p->from, v)) + return 4; + if(copyau1(p, v)) + return 4; + return 3; + } + if(copyau(&p->from, v)) + return 1; + if(copyau1(p, v)) + return 1; + if(copyau(&p->to, v)) + return 1; + return 0; - case ADIVB: - case ADIVL: - case ADIVQ: - case ADIVW: - case AIDIVB: - case AIDIVL: - case AIDIVQ: - case AIDIVW: - case AIMULB: - case AMULB: - case AMULL: - case AMULQ: - case AMULW: + case ABEQ: /* read, read */ + case ABNE: + case ABCS: + case ABHS: + case ABCC: + case ABLO: + case ABMI: + case ABPL: + case ABVS: + case ABVC: + case ABHI: + case ABLS: + case ABGE: + case ABLT: + case ABGT: + case ABLE: + if(s != A) { + if(copysub(&p->from, v, s, 1)) + return 1; + return copysub1(p, v, s, 1); + } + if(copyau(&p->from, v)) + return 1; + if(copyau1(p, v)) + return 1; + return 0; - case ACWD: - case ACDQ: - case ACQO: - if(v->type == D_AX || v->type == D_DX) - return 2; - goto caseread; - - case AMOVSL: - case AMOVSQ: - case AREP: - case AREPN: - if(v->type == D_CX || v->type == D_DI || v->type == D_SI) - return 2; - goto caseread; - - case AJMP: /* funny */ + case AB: /* funny */ if(s != A) { if(copysub(&p->to, v, s, 1)) return 1; @@ -744,17 +1089,23 @@ return 0; case ARET: /* funny */ - if(v->type == REGRET || v->type == FREGRET) + if(v->type == D_REG) + if(v->reg == REGRET) return 2; - if(s != A) - return 1; - return 3; + if(v->type == D_FREG) + if(v->reg == FREGRET) + return 2; - case ACALL: /* funny */ - if(REGEXT && v->type <= REGEXT && v->type > exregoffset) - return 2; - if(REGARG && v->type == REGARG) - return 2; + case ABL: /* funny */ + if(v->type == D_REG) { + if(v->reg <= REGEXT && v->reg > exregoffset) + return 2; + if(v->reg == (uchar)REGARG) + return 2; + } + if(v->type == D_FREG) + if(v->reg <= FREGEXT && v->reg > exfregoffset) + return 2; if(s != A) { if(copysub(&p->to, v, s, 1)) @@ -766,11 +1117,50 @@ return 3; case ATEXT: /* funny */ - if(REGARG && v->type == REGARG) - return 3; + if(v->type == D_REG) + if(v->reg == (uchar)REGARG) + return 3; return 0; } - return 0; +} + +int +a2type(Prog *p) +{ + + switch(p->as) { + + case ACMP: + case ACMN: + + case AADD: + case ASUB: + case ARSB: + case ASLL: + case ASRL: + case ASRA: + case AORR: + case AAND: + case AEOR: + case AMUL: + case ADIV: + case ADIVU: + return D_REG; + + case ACMPF: + case ACMPD: + + case AADDF: + case AADDD: + case ASUBF: + case ASUBD: + case AMULF: + case AMULD: + case ADIVF: + case ADIVD: + return D_FREG; + } + return D_NONE; } /* @@ -781,13 +1171,19 @@ int copyas(Adr *a, Adr *v) { - if(a->type != v->type) - return 0; - if(regtyp(v)) - return 1; - if(v->type == D_AUTO || v->type == D_PARAM) - if(v->offset == a->offset) + + if(regtyp(v)) { + if(a->type == v->type) + if(a->reg == v->reg) return 1; + } else if(v->type == D_CONST) { /* for constprop */ + if(a->type == v->type) + if(a->name == v->name) + if(a->sym == v->sym) + if(a->reg == v->reg) + if(a->offset == v->offset) + return 1; + } return 0; } @@ -800,11 +1196,31 @@ if(copyas(a, v)) return 1; + if(v->type == D_REG) { + if(a->type == D_OREG) { + if(v->reg == a->reg) + return 1; + } else if(a->type == D_SHIFT) { + if((a->offset&0xf) == v->reg) + return 1; + if((a->offset&(1<<4)) && (a->offset>>8) == v->reg) + return 1; + } + } + return 0; +} + +int +copyau1(Prog *p, Adr *v) +{ + if(regtyp(v)) { - if(a->type-D_INDIR == v->type) + if(a2type(p) == v->type) + if(p->reg == v->reg) { + if(a2type(p) != v->type) + print("botch a2type %P\n", p); return 1; - if(a->index == v->type) - return 1; + } } return 0; } @@ -816,31 +1232,237 @@ int copysub(Adr *a, Adr *v, Adr *s, int f) { - int t; - if(copyas(a, v)) { - t = s->type; - if(t >= D_AX && t <= D_R15 || t >= D_X0 && t <= D_X0+15) { - if(f) - a->type = t; - } - return 0; - } - if(regtyp(v)) { - t = v->type; - if(a->type == t+D_INDIR) { - if((s->type == D_BP || s->type == D_R13) && a->index != D_NONE) - return 1; /* can't use BP-base with index */ - if(f) - a->type = s->type+D_INDIR; -// return 0; - } - if(a->index == t) { - if(f) - a->index = s->type; - return 0; - } - return 0; + if(f) + if(copyau(a, v)) { + if(a->type == D_SHIFT) { + if((a->offset&0xf) == v->reg) + a->offset = (a->offset&~0xf)|s->reg; + if((a->offset&(1<<4)) && (a->offset>>8) == v->reg) + a->offset = (a->offset&~(0xf<<8))|(s->reg<<8); + } else + a->reg = s->reg; } return 0; } + +int +copysub1(Prog *p1, Adr *v, Adr *s, int f) +{ + + if(f) + if(copyau1(p1, v)) + p1->reg = s->reg; + return 0; +} + +struct { + int opcode; + int notopcode; + int scond; + int notscond; +} predinfo[] = { + { ABEQ, ABNE, 0x0, 0x1, }, + { ABNE, ABEQ, 0x1, 0x0, }, + { ABCS, ABCC, 0x2, 0x3, }, + { ABHS, ABLO, 0x2, 0x3, }, + { ABCC, ABCS, 0x3, 0x2, }, + { ABLO, ABHS, 0x3, 0x2, }, + { ABMI, ABPL, 0x4, 0x5, }, + { ABPL, ABMI, 0x5, 0x4, }, + { ABVS, ABVC, 0x6, 0x7, }, + { ABVC, ABVS, 0x7, 0x6, }, + { ABHI, ABLS, 0x8, 0x9, }, + { ABLS, ABHI, 0x9, 0x8, }, + { ABGE, ABLT, 0xA, 0xB, }, + { ABLT, ABGE, 0xB, 0xA, }, + { ABGT, ABLE, 0xC, 0xD, }, + { ABLE, ABGT, 0xD, 0xC, }, +}; + +typedef struct { + Reg *start; + Reg *last; + Reg *end; + int len; +} Joininfo; + +enum { + Join, + Split, + End, + Branch, + Setcond, + Toolong +}; + +enum { + Falsecond, + Truecond, + Delbranch, + Keepbranch +}; + +int +isbranch(Prog *p) +{ + return (ABEQ <= p->as) && (p->as <= ABLE); +} + +int +predicable(Prog *p) +{ + if (isbranch(p) + || p->as == ANOP + || p->as == AXXX + || p->as == ADATA + || p->as == AGLOBL + || p->as == AGOK + || p->as == AHISTORY + || p->as == ANAME + || p->as == ASIGNAME + || p->as == ATEXT + || p->as == AWORD + || p->as == ABCASE + || p->as == ACASE) + return 0; + return 1; +} + +/* + * Depends on an analysis of the encodings performed by 5l. + * These seem to be all of the opcodes that lead to the "S" bit + * being set in the instruction encodings. + * + * C_SBIT may also have been set explicitly in p->scond. + */ +int +modifiescpsr(Prog *p) +{ + return (p->scond&C_SBIT) + || p->as == ATST + || p->as == ATEQ + || p->as == ACMN + || p->as == ACMP + || p->as == AMULU + || p->as == ADIVU + || p->as == AMUL + || p->as == ADIV + || p->as == AMOD + || p->as == AMODU + || p->as == ABL; +} + +/* + * Find the maximal chain of instructions starting with r which could + * be executed conditionally + */ +int +joinsplit(Reg *r, Joininfo *j) +{ + j->start = r; + j->last = r; + j->len = 0; + do { + if (r->p2 && (r->p1 || r->p2->p2link)) { + j->end = r; + return Join; + } + if (r->s1 && r->s2) { + j->end = r; + return Split; + } + j->last = r; + if (r->prog->as != ANOP) + j->len++; + if (!r->s1 && !r->s2) { + j->end = r->link; + return End; + } + if (r->s2) { + j->end = r->s2; + return Branch; + } + if (modifiescpsr(r->prog)) { + j->end = r->s1; + return Setcond; + } + r = r->s1; + } while (j->len < 4); + j->end = r; + return Toolong; +} + +Reg * +successor(Reg *r) +{ + if (r->s1) + return r->s1; + else + return r->s2; +} + +void +applypred(Reg *rstart, Joininfo *j, int cond, int branch) +{ + int pred; + Reg *r; + + if(j->len == 0) + return; + if (cond == Truecond) + pred = predinfo[rstart->prog->as - ABEQ].scond; + else + pred = predinfo[rstart->prog->as - ABEQ].notscond; + + for (r = j->start; ; r = successor(r)) { + if (r->prog->as == AB) { + if (r != j->last || branch == Delbranch) + excise(r); + else { + if (cond == Truecond) + r->prog->as = predinfo[rstart->prog->as - ABEQ].opcode; + else + r->prog->as = predinfo[rstart->prog->as - ABEQ].notopcode; + } + } + else if (predicable(r->prog)) + r->prog->scond = (r->prog->scond&~C_SCOND)|pred; + if (r->s1 != r->link) { + r->s1 = r->link; + r->link->p1 = r; + } + if (r == j->last) + break; + } +} + +void +predicate(void) +{ + Reg *r; + int t1, t2; + Joininfo j1, j2; + + for(r=firstr; r!=R; r=r->link) { + if (isbranch(r->prog)) { + t1 = joinsplit(r->s1, &j1); + t2 = joinsplit(r->s2, &j2); + if(j1.last->link != j2.start) + continue; + if(j1.end == j2.end) + if((t1 == Branch && (t2 == Join || t2 == Setcond)) || + (t2 == Join && (t1 == Join || t1 == Setcond))) { + applypred(r, &j1, Falsecond, Delbranch); + applypred(r, &j2, Truecond, Delbranch); + excise(r); + continue; + } + if(t1 == End || t1 == Branch) { + applypred(r, &j1, Falsecond, Keepbranch); + excise(r); + continue; + } + } + } +} diff -r d8d00747375b sys/src/cmd/6c/reg.c --- a/sys/src/cmd/6c/reg.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/6c/reg.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,5 +1,38 @@ +// Inferno utils/5c/reg.c +// http://code.google.com/p/inferno-os/source/browse/utils/5c/reg.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 "gc.h" +void addsplits(void); + Reg* rega(void) { @@ -33,23 +66,29 @@ void regopt(Prog *p) { + USED(p); + // TODO(kaib): optimizer disabled because it smashes R8 when running out of registers + // the disable is unconventionally here because the call is in common code shared by 5c/6c/8c + return; + +#ifdef NOTDEF Reg *r, *r1, *r2; Prog *p1; int i, z; - long initpc, val, npc; - ulong vreg; + int32 initpc, val, npc; + uint32 vreg; Bits bit; struct { - long m; - long c; + int32 m; + int32 c; Reg* p; } log5[6], *lp; firstr = R; lastr = R; nvar = 0; - regbits = RtoB(D_SP) | RtoB(D_AX) | RtoB(D_X0); + regbits = 0; for(z=0; zprog->as) { case ARET: - case AJMP: - case AIRETL: - case AIRETQ: + case AB: + case ARFE: r->p1 = R; r1->s1 = R; } - bit = mkvar(r, &p->from); - if(bany(&bit)) - switch(p->as) { /* - * funny + * left side always read */ - case ALEAL: - case ALEAQ: - for(z=0; zfrom, p->as==AMOVW); + for(z=0; zuse1.b[z] |= bit.b[z]; /* - * left side read + * right side depends on opcode */ - default: - for(z=0; zuse1.b[z] |= bit.b[z]; - break; - } - - bit = mkvar(r, &p->to); + bit = mkvar(&p->to, 0); if(bany(&bit)) switch(p->as) { default: - diag(Z, "reg: unknown op: %A", p->as); - break; - - /* - * right side read - */ - case ACMPB: - case ACMPL: - case ACMPQ: - case ACMPW: - case ACOMISS: - case ACOMISD: - case AUCOMISS: - case AUCOMISD: - for(z=0; zuse2.b[z] |= bit.b[z]; + diag(Z, "reg: unknown asop: %A", p->as); break; /* * right side write */ case ANOP: - case AMOVL: - case AMOVQ: case AMOVB: + case AMOVBU: + case AMOVH: + case AMOVHU: case AMOVW: - case AMOVBLSX: - case AMOVBLZX: - case AMOVBQSX: - case AMOVBQZX: - case AMOVLQSX: - case AMOVLQZX: - case AMOVWLSX: - case AMOVWLZX: - case AMOVWQSX: - case AMOVWQZX: - - case AMOVSS: - case AMOVSD: - case ACVTSD2SL: - case ACVTSD2SQ: - case ACVTSD2SS: - case ACVTSL2SD: - case ACVTSL2SS: - case ACVTSQ2SD: - case ACVTSQ2SS: - case ACVTSS2SD: - case ACVTSS2SL: - case ACVTSS2SQ: - case ACVTTSD2SL: - case ACVTTSD2SQ: - case ACVTTSS2SL: - case ACVTTSS2SQ: + case AMOVF: + case AMOVD: for(z=0; zset.b[z] |= bit.b[z]; break; /* - * right side read+write - */ - case AADDB: - case AADDL: - case AADDQ: - case AADDW: - case AANDB: - case AANDL: - case AANDQ: - case AANDW: - case ASUBB: - case ASUBL: - case ASUBQ: - case ASUBW: - case AORB: - case AORL: - case AORQ: - case AORW: - case AXORB: - case AXORL: - case AXORQ: - case AXORW: - case ASALB: - case ASALL: - case ASALQ: - case ASALW: - case ASARB: - case ASARL: - case ASARQ: - case ASARW: - case AROLB: - case AROLL: - case AROLQ: - case AROLW: - case ARORB: - case ARORL: - case ARORQ: - case ARORW: - case ASHLB: - case ASHLL: - case ASHLQ: - case ASHLW: - case ASHRB: - case ASHRL: - case ASHRQ: - case ASHRW: - case AIMULL: - case AIMULQ: - case AIMULW: - case ANEGL: - case ANEGQ: - case ANOTL: - case ANOTQ: - case AADCL: - case AADCQ: - case ASBBL: - case ASBBQ: - - case AADDSD: - case AADDSS: - case ACMPSD: - case ACMPSS: - case ADIVSD: - case ADIVSS: - case AMAXSD: - case AMAXSS: - case AMINSD: - case AMINSS: - case AMULSD: - case AMULSS: - case ARCPSS: - case ARSQRTSS: - case ASQRTSD: - case ASQRTSS: - case ASUBSD: - case ASUBSS: - case AXORPD: - for(z=0; zset.b[z] |= bit.b[z]; - r->use2.b[z] |= bit.b[z]; - } - break; - - /* * funny */ - case ACALL: + case ABL: for(z=0; zas) { - case AIMULL: - case AIMULQ: - case AIMULW: - if(p->to.type != D_NONE) - break; - - case AIDIVB: - case AIDIVL: - case AIDIVQ: - case AIDIVW: - case AIMULB: - case ADIVB: - case ADIVL: - case ADIVQ: - case ADIVW: - case AMULB: - case AMULL: - case AMULQ: - case AMULW: - - case ACWD: - case ACDQ: - case ACQO: - r->regu |= RtoB(D_AX) | RtoB(D_DX); - break; - - case AREP: - case AREPN: - case ALOOP: - case ALOOPEQ: - case ALOOPNE: - r->regu |= RtoB(D_CX); - break; - - case AMOVSB: - case AMOVSL: - case AMOVSQ: - case AMOVSW: - case ACMPSB: - case ACMPSL: - case ACMPSQ: - case ACMPSW: - r->regu |= RtoB(D_SI) | RtoB(D_DI); - break; - - case ASTOSB: - case ASTOSL: - case ASTOSQ: - case ASTOSW: - case ASCASB: - case ASCASL: - case ASCASQ: - case ASCASW: - r->regu |= RtoB(D_AX) | RtoB(D_DI); - break; - - case AINSB: - case AINSL: - case AINSW: - case AOUTSB: - case AOUTSL: - case AOUTSW: - r->regu |= RtoB(D_DI) | RtoB(D_DX); - break; + if(p->as == AMOVM) { + if(p->from.type == D_CONST) + z = p->from.offset; + else + z = p->to.offset; + for(i=0; z; i++) { + if(z&1) + regbits |= RtoB(i); + z >>= 1; + } } } if(firstr == R) @@ -415,26 +264,6 @@ r->active = 0; change = 0; loopit(firstr, npc); - if(debug['R'] && debug['v']) { - print("\nlooping structure:\n"); - for(r = firstr; r != R; r = r->link) { - print("%ld:%P", r->loop, r->prog); - for(z=0; zuse1.b[z] | - r->use2.b[z] | - r->set.b[z]; - if(bany(&bit)) { - print("\t"); - if(bany(&r->use1)) - print(" u1=%B", r->use1); - if(bany(&r->use2)) - print(" u2=%B", r->use2); - if(bany(&r->set)) - print(" st=%B", r->set); - } - print("\n"); - } - } /* * pass 3 @@ -477,6 +306,37 @@ if(change) goto loop2; + addsplits(); + + if(debug['R'] && debug['v']) { + print("\nprop structure:\n"); + for(r = firstr; r != R; r = r->link) { + print("%d:%P", r->loop, r->prog); + for(z=0; zset.b[z] | + r->refahead.b[z] | r->calahead.b[z] | + r->refbehind.b[z] | r->calbehind.b[z] | + r->use1.b[z] | r->use2.b[z]; + if(bany(&bit)) { + print("\t"); + if(bany(&r->use1)) + print(" u1=%B", r->use1); + if(bany(&r->use2)) + print(" u2=%B", r->use2); + if(bany(&r->set)) + print(" st=%B", r->set); + if(bany(&r->refahead)) + print(" ra=%B", r->refahead); + if(bany(&r->calahead)) + print(" ca=%B", r->calahead); + if(bany(&r->refbehind)) + print(" rb=%B", r->refbehind); + if(bany(&r->calbehind)) + print(" cb=%B", r->calbehind); + } + print("\n"); + } + } /* * pass 5 @@ -495,23 +355,12 @@ print("used and not set: %B\n", bit); } } - if(debug['R'] && debug['v']) - print("\nprop structure:\n"); + for(r = firstr; r != R; r = r->link) r->act = zbits; rgp = region; nregion = 0; for(r = firstr; r != R; r = r->link) { - if(debug['R'] && debug['v']) { - print("%P\t", r->prog); - if(bany(&r->set)) - print("s:%B ", r->set); - if(bany(&r->refahead)) - print("ra:%B ", r->refahead); - if(bany(&r->calahead)) - print("ca:%B ", r->calahead); - print("\n"); - } for(z=0; zset.b[z] & ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]); @@ -535,7 +384,7 @@ bit.b[i/32] &= ~(1L<<(i%32)); if(change <= 0) { if(debug['R']) - print("%L$%d: %B\n", + print("%L $%d: %B\n", r->prog->lineno, change, blsh(i)); continue; } @@ -562,11 +411,18 @@ vreg = paint2(rgp->enter, rgp->varno); vreg = allreg(vreg, rgp); if(debug['R']) { - print("%L$%d %R: %B\n", - rgp->enter->prog->lineno, - rgp->cost, - rgp->regno, - bit); + if(rgp->regno >= NREG) + print("%L $%d F%d: %B\n", + rgp->enter->prog->lineno, + rgp->cost, + rgp->regno-NREG, + bit); + else + print("%L $%d R%d: %B\n", + rgp->enter->prog->lineno, + rgp->cost, + rgp->regno, + bit); } if(rgp->regno != 0) paint3(rgp->enter, rgp->varno, vreg, rgp->regno); @@ -636,6 +492,34 @@ r1->link = freer; freer = firstr; } +#endif +} + +void +addsplits(void) +{ + Reg *r, *r1; + int z, i; + Bits bit; + + for(r = firstr; r != R; r = r->link) { + if(r->loop > 1) + continue; + if(r->prog->as == ABL) + continue; + for(r1 = r->p2; r1 != R; r1 = r1->p2link) { + if(r1->loop <= 1) + continue; + for(z=0; zcalbehind.b[z] & + (r->refahead.b[z] | r->use1.b[z] | r->use2.b[z]) & + ~(r->calahead.b[z] & addrs.b[z]); + while(bany(&bit)) { + i = bnum(bit); + bit.b[i/32] &= ~(1L << (i%32)); + } + } + } } /* @@ -661,98 +545,75 @@ a = &p1->to; a->sym = v->sym; + a->name = v->name; a->offset = v->offset; a->etype = v->etype; - a->type = v->name; + a->type = D_OREG; + if(a->etype == TARRAY || a->sym == S) + a->type = D_CONST; - p1->as = AMOVL; + p1->as = AMOVW; if(v->etype == TCHAR || v->etype == TUCHAR) p1->as = AMOVB; if(v->etype == TSHORT || v->etype == TUSHORT) - p1->as = AMOVW; - if(v->etype == TVLONG || v->etype == TUVLONG || v->etype == TIND) - p1->as = AMOVQ; + p1->as = AMOVH; if(v->etype == TFLOAT) - p1->as = AMOVSS; + p1->as = AMOVF; if(v->etype == TDOUBLE) - p1->as = AMOVSD; + p1->as = AMOVD; - p1->from.type = rn; + p1->from.type = D_REG; + p1->from.reg = rn; + if(rn >= NREG) { + p1->from.type = D_FREG; + p1->from.reg = rn-NREG; + } if(!f) { p1->from = *a; *a = zprog.from; - a->type = rn; + a->type = D_REG; + a->reg = rn; + if(rn >= NREG) { + a->type = D_FREG; + a->reg = rn-NREG; + } if(v->etype == TUCHAR) - p1->as = AMOVB; + p1->as = AMOVBU; if(v->etype == TUSHORT) - p1->as = AMOVW; + p1->as = AMOVHU; } if(debug['R']) print("%P\t.a%P\n", p, p1); } -ulong -doregbits(int r) -{ - ulong b; - - b = 0; - if(r >= D_INDIR) - r -= D_INDIR; - if(r >= D_AX && r <= D_R15) - b |= RtoB(r); - else - if(r >= D_AL && r <= D_R15B) - b |= RtoB(r-D_AL+D_AX); - else - if(r >= D_AH && r <= D_BH) - b |= RtoB(r-D_AH+D_AX); - else - if(r >= D_X0 && r <= D_X0+15) - b |= FtoB(r); - return b; -} - Bits -mkvar(Reg *r, Adr *a) +mkvar(Adr *a, int docon) { Var *v; int i, t, n, et, z; - long o; + int32 o; Bits bit; Sym *s; - /* - * mark registers used - */ t = a->type; - r->regu |= doregbits(t); - r->regu |= doregbits(a->index); + if(t == D_REG && a->reg != NREG) + regbits |= RtoB(a->reg); + if(t == D_FREG && a->reg != NREG) + regbits |= FtoB(a->reg); + s = a->sym; + o = a->offset; + et = a->etype; + if(s == S) { + if(t != D_CONST || !docon || a->reg != NREG) + goto none; + et = TLONG; + } + if(t == D_CONST) { + if(s == S && sval(o)) + goto none; + } - switch(t) { - default: - goto none; - case D_ADDR: - a->type = a->index; - bit = mkvar(r, a); - for(z=0; ztype = t; - goto none; - case D_EXTERN: - case D_STATIC: - case D_PARAM: - case D_AUTO: - n = t; - break; - } - s = a->sym; - if(s == S) - goto none; - if(s->name[0] == '.') - goto none; - et = a->etype; - o = a->offset; + n = a->name; v = var; for(i=0; isym) @@ -761,6 +622,9 @@ goto out; v++; } + if(s) + if(s->name[0] == '.') + goto none; if(nvar >= NVAR) { if(debug['w'] > 1 && s) warn(Z, "variable not optimized: %s", s->name); @@ -771,11 +635,10 @@ v = &var[i]; v->sym = s; v->offset = o; + v->etype = et; v->name = n; - v->etype = et; if(debug['R']) print("bit=%2d et=%2d %D\n", i, et, a); - out: bit = blsh(i); if(n == D_EXTERN || n == D_STATIC) @@ -784,10 +647,24 @@ if(n == D_PARAM) for(z=0; zetype != et || !(typechlpfd[et] || typev[et])) /* funny punning */ + if(v->etype != et || !typechlpfd[et]) /* funny punning */ for(z=0; zprog->as) { - case ACALL: + case ABL: for(z=0; z r) s = idom[s]; @@ -913,9 +790,9 @@ } int -loophead(long *idom, Reg *r) +loophead(int32 *idom, Reg *r) { - long src; + int32 src; src = r->rpo; if(r->p1 != R && doms(idom, src, r->p1->rpo)) @@ -927,7 +804,7 @@ } void -loopmark(Reg **rpo2r, long head, Reg *r) +loopmark(Reg **rpo2r, int32 head, Reg *r) { if(r->rpo < head || r->active == head) return; @@ -940,17 +817,16 @@ } void -loopit(Reg *r, long nr) +loopit(Reg *r, int32 nr) { Reg *r1; - long i, d, me; + int32 i, d, me; if(nr > maxnr) { rpo2r = alloc(nr * sizeof(Reg*)); - idom = alloc(nr * sizeof(long)); + idom = alloc(nr * sizeof(int32)); maxnr = nr; } - d = postorder(r, rpo2r, 0); if(d > nr) fatal(Z, "too many reg nodes"); @@ -1010,8 +886,8 @@ } } -ulong -allreg(ulong b, Rgn *r) +uint32 +allreg(uint32 b, Rgn *r) { Var *v; int i; @@ -1032,22 +908,21 @@ case TUINT: case TLONG: case TULONG: - case TVLONG: - case TUVLONG: case TIND: case TARRAY: i = BtoR(~b); - if(i && r->cost > 0) { + if(i && r->cost >= 0) { r->regno = i; return RtoB(i); } break; + case TVLONG: case TDOUBLE: case TFLOAT: i = BtoF(~b); - if(i && r->cost > 0) { - r->regno = i; + if(i && r->cost >= 0) { + r->regno = i+NREG; return FtoB(i); } break; @@ -1061,7 +936,7 @@ Reg *r1; Prog *p; int z; - ulong bb; + uint32 bb; z = bn/32; bb = 1L<<(bn%32); @@ -1080,10 +955,10 @@ r = r1; } - if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) { + if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb) { change -= CLOAD * r->loop; if(debug['R'] && debug['v']) - print("%ld%P\tld %B $%d\n", r->loop, + print("%d%P\td %B $%d\n", r->loop, r->prog, blsh(bn), change); } for(;;) { @@ -1093,21 +968,21 @@ if(r->use1.b[z] & bb) { change += CREF * r->loop; if(debug['R'] && debug['v']) - print("%ld%P\tu1 %B $%d\n", r->loop, + print("%d%P\tu1 %B $%d\n", r->loop, p, blsh(bn), change); } if((r->use2.b[z]|r->set.b[z]) & bb) { change += CREF * r->loop; if(debug['R'] && debug['v']) - print("%ld%P\tu2 %B $%d\n", r->loop, + print("%d%P\tu2 %B $%d\n", r->loop, p, blsh(bn), change); } if(STORE(r) & r->regdiff.b[z] & bb) { change -= CLOAD * r->loop; if(debug['R'] && debug['v']) - print("%ld%P\tst %B $%d\n", r->loop, + print("%d%P\tst %B $%d\n", r->loop, p, blsh(bn), change); } @@ -1132,52 +1007,12 @@ } } -ulong -regset(Reg *r, ulong bb) -{ - ulong b, set; - Adr v; - int c; - - set = 0; - v = zprog.from; - while(b = bb & ~(bb-1)) { - v.type = b & 0xFFFF? BtoR(b): BtoF(b); - if(v.type == 0) - diag(Z, "zero v.type for %#lux", b); - c = copyu(r->prog, &v, A); - if(c == 3) - set |= b; - bb &= ~b; - } - return set; -} - -ulong -reguse(Reg *r, ulong bb) -{ - ulong b, set; - Adr v; - int c; - - set = 0; - v = zprog.from; - while(b = bb & ~(bb-1)) { - v.type = b & 0xFFFF? BtoR(b): BtoF(b); - c = copyu(r->prog, &v, A); - if(c == 1 || c == 2 || c == 4) - set |= b; - bb &= ~b; - } - return set; -} - -ulong +uint32 paint2(Reg *r, int bn) { Reg *r1; int z; - ulong bb, vreg, x; + uint32 bb, vreg; z = bn/32; bb = 1L << (bn%32); @@ -1220,25 +1055,16 @@ if(!(r->refbehind.b[z] & bb)) break; } - - bb = vreg; - for(; r; r=r->s1) { - x = r->regu & ~bb; - if(x) { - vreg |= reguse(r, x); - bb |= regset(r, x); - } - } return vreg; } void -paint3(Reg *r, int bn, long rb, int rn) +paint3(Reg *r, int bn, int32 rb, int rn) { Reg *r1; Prog *p; int z; - ulong bb; + uint32 bb; z = bn/32; bb = 1L << (bn%32); @@ -1308,49 +1134,62 @@ { a->sym = 0; - a->offset = 0; - a->type = rn; -} - -long -RtoB(int r) -{ - - if(r < D_AX || r > D_R15) - return 0; - return 1L << (r-D_AX); -} - -int -BtoR(long b) -{ - - b &= 0xffffL; - if(b == 0) - return 0; - return bitno(b) + D_AX; + a->name = D_NONE; + a->type = D_REG; + a->reg = rn; + if(rn >= NREG) { + a->type = D_FREG; + a->reg = rn-NREG; + } } /* * bit reg - * 16 X5 - * 17 X6 - * 18 X7 + * 0 R0 + * 1 R1 + * ... ... + * 10 R10 */ -long -FtoB(int f) +int32 +RtoB(int r) { - if(f < FREGMIN || f > FREGEXT) + + if(r < 2 || r >= REGTMP-2) // excluded R9 and R10 for m and g return 0; - return 1L << (f - FREGMIN + 16); + return 1L << r; } int -BtoF(long b) +BtoR(int32 b) +{ + b &= 0x01fcL; // excluded R9 and R10 for m and g + if(b == 0) + return 0; + return bitno(b); +} + +/* + * bit reg + * 18 F2 + * 19 F3 + * ... ... + * 23 F7 + */ +int32 +FtoB(int f) { - b &= 0x70000L; + if(f < 2 || f > NFREG-1) + return 0; + return 1L << (f + 16); +} + +int +BtoF(int32 b) +{ + + b &= 0xfc0000L; if(b == 0) return 0; - return bitno(b) - 16 + FREGMIN; + return bitno(b) - 16; } diff -r d8d00747375b sys/src/cmd/6c/sgen.c --- a/sys/src/cmd/6c/sgen.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/6c/sgen.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,238 +1,189 @@ +// Inferno utils/5c/sgen.c +// http://code.google.com/p/inferno-os/source/browse/utils/5c/sgen.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 "gc.h" +Prog* +gtext(Sym *s, int32 stkoff) +{ + int32 a; + + a = 0; + if(!(textflag & NOSPLIT)) + a = argsize(); + else if(stkoff >= 128) + yyerror("stack frame too large for NOSPLIT function"); + + gpseudo(ATEXT, s, nodconst(stkoff)); + p->to.type = D_CONST2; + p->to.offset2 = a; + return p; +} + void noretval(int n) { if(n & 1) { gins(ANOP, Z, Z); - p->to.type = REGRET; + p->to.type = D_REG; + p->to.reg = REGRET; } if(n & 2) { gins(ANOP, Z, Z); - p->to.type = FREGRET; - } -} - -/* welcome to commute */ -static void -commute(Node *n) -{ - Node *l, *r; - - l = n->left; - r = n->right; - if(r->complex > l->complex) { - n->left = r; - n->right = l; - } -} - -void -indexshift(Node *n) -{ - int g; - - if(!typechlpv[n->type->etype]) - return; - simplifyshift(n); - if(n->op == OASHL && n->right->op == OCONST){ - g = vconst(n->right); - if(g >= 0 && g <= 3) - n->addable = 7; + p->to.type = D_FREG; + p->to.reg = FREGRET; } } /* * calculate addressability as follows - * NAME ==> 10/11 name+value(SB/SP) - * REGISTER ==> 12 register * CONST ==> 20 $value - * *(20) ==> 21 value - * &(10) ==> 13 $name+value(SB) - * &(11) ==> 1 $name+value(SP) - * (13) + (20) ==> 13 fold constants - * (1) + (20) ==> 1 fold constants - * *(13) ==> 10 back to name - * *(1) ==> 11 back to name - * - * (20) * (X) ==> 7 multiplier in indexing - * (X,7) + (13,1) ==> 8 adder in indexing (addresses) - * (8) ==> &9(OINDEX) index, almost addressable - * + * NAME ==> 10 name + * REGISTER ==> 11 register + * INDREG ==> 12 *[(reg)+offset] + * &10 ==> 2 $name + * ADD(2, 20) ==> 2 $name+offset + * ADD(3, 20) ==> 3 $(reg)+offset + * &12 ==> 3 $(reg)+offset + * *11 ==> 11 ?? + * *2 ==> 10 name + * *3 ==> 12 *(reg)+offset * calculate complexity (number of registers) */ void xcom(Node *n) { Node *l, *r; - int g; + int t; if(n == Z) return; l = n->left; r = n->right; + n->addable = 0; n->complex = 0; - n->addable = 0; switch(n->op) { case OCONST: n->addable = 20; - break; + return; + + case OREGISTER: + n->addable = 11; + return; + + case OINDREG: + n->addable = 12; + return; case ONAME: n->addable = 10; - if(n->class == CPARAM || n->class == CAUTO) - n->addable = 11; - break; - - case OREGISTER: - n->addable = 12; - break; - - case OINDREG: - n->addable = 12; - break; + return; case OADDR: xcom(l); if(l->addable == 10) - n->addable = 13; - else + n->addable = 2; + if(l->addable == 12) + n->addable = 3; + break; + + case OIND: + xcom(l); if(l->addable == 11) - n->addable = 1; + n->addable = 12; + if(l->addable == 3) + n->addable = 12; + if(l->addable == 2) + n->addable = 10; break; case OADD: xcom(l); xcom(r); - if(n->type->etype != TIND) - break; - - switch(r->addable) { - case 20: - switch(l->addable) { - case 1: - case 13: - commadd: - l->type = n->type; - *n = *l; - l = new(0, Z, Z); - *l = *(n->left); - l->xoffset += r->vconst; - n->left = l; - r = n->right; - goto brk; - } - break; - - case 1: - case 13: - case 10: - case 11: - /* l is the base, r is the index */ - if(l->addable != 20) - n->addable = 8; - break; + if(l->addable == 20) { + if(r->addable == 2) + n->addable = 2; + if(r->addable == 3) + n->addable = 3; } - switch(l->addable) { - case 20: - switch(r->addable) { - case 13: - case 1: - r = n->left; - l = n->right; - n->left = l; - n->right = r; - goto commadd; - } - break; - - case 13: - case 1: - case 10: - case 11: - /* r is the base, l is the index */ - if(r->addable != 20) - n->addable = 8; - break; - } - if(n->addable == 8 && !side(n)) { - indx(n); - l = new1(OINDEX, idx.basetree, idx.regtree); - l->scale = idx.scale; - l->addable = 9; - l->complex = l->right->complex; - l->type = l->left->type; - n->op = OADDR; - n->left = l; - n->right = Z; - n->addable = 8; - break; + if(r->addable == 20) { + if(l->addable == 2) + n->addable = 2; + if(l->addable == 3) + n->addable = 3; } break; - case OINDEX: + case OASLMUL: + case OASMUL: xcom(l); xcom(r); - n->addable = 9; - break; - - case OIND: - xcom(l); - if(l->op == OADDR) { - l = l->left; - l->type = n->type; - *n = *l; - return; + t = vlog(r); + if(t >= 0) { + n->op = OASASHL; + r->vconst = t; + r->type = types[TINT]; } - switch(l->addable) { - case 20: - n->addable = 21; - break; - case 1: - n->addable = 11; - break; - case 13: - n->addable = 10; - break; - } - break; - - case OASHL: - xcom(l); - xcom(r); - indexshift(n); break; case OMUL: case OLMUL: xcom(l); xcom(r); - g = vlog(l); - if(g >= 0) { + t = vlog(r); + if(t >= 0) { + n->op = OASHL; + r->vconst = t; + r->type = types[TINT]; + } + t = vlog(l); + if(t >= 0) { + n->op = OASHL; n->left = r; n->right = l; - l = r; - r = n->right; + r = l; + l = n->left; + r->vconst = t; + r->type = types[TINT]; } - g = vlog(r); - if(g >= 0) { - n->op = OASHL; - r->vconst = g; - r->type = types[TINT]; - indexshift(n); - break; - } - commute(n); break; case OASLDIV: xcom(l); xcom(r); - g = vlog(r); - if(g >= 0) { + t = vlog(r); + if(t >= 0) { n->op = OASLSHR; - r->vconst = g; + r->vconst = t; r->type = types[TINT]; } break; @@ -240,21 +191,19 @@ case OLDIV: xcom(l); xcom(r); - g = vlog(r); - if(g >= 0) { + t = vlog(r); + if(t >= 0) { n->op = OLSHR; - r->vconst = g; + r->vconst = t; r->type = types[TINT]; - indexshift(n); - break; } break; case OASLMOD: xcom(l); xcom(r); - g = vlog(r); - if(g >= 0) { + t = vlog(r); + if(t >= 0) { n->op = OASAND; r->vconst--; } @@ -263,31 +212,13 @@ case OLMOD: xcom(l); xcom(r); - g = vlog(r); - if(g >= 0) { + t = vlog(r); + if(t >= 0) { n->op = OAND; r->vconst--; } break; - case OASMUL: - case OASLMUL: - xcom(l); - xcom(r); - g = vlog(r); - if(g >= 0) { - n->op = OASASHL; - r->vconst = g; - } - break; - - case OLSHR: - case OASHR: - xcom(l); - xcom(r); - indexshift(n); - break; - default: if(l != Z) xcom(l); @@ -295,9 +226,9 @@ xcom(r); break; } -brk: if(n->addable >= 10) return; + if(l != Z) n->complex = l->complex; if(r != Z) { @@ -310,61 +241,20 @@ if(n->complex == 0) n->complex++; + if(com64(n)) + return; + switch(n->op) { - case OFUNC: n->complex = FNX; break; - case OCAST: - if(l->type->etype == TUVLONG && typefd[n->type->etype]) - n->complex += 2; - break; - - case OLMOD: - case OMOD: - case OLMUL: - case OLDIV: - case OMUL: - case ODIV: - case OASLMUL: - case OASLDIV: - case OASLMOD: - case OASMUL: - case OASDIV: - case OASMOD: - if(r->complex >= l->complex) { - n->complex = l->complex + 3; - if(r->complex > n->complex) - n->complex = r->complex; - } else { - n->complex = r->complex + 3; - if(l->complex > n->complex) - n->complex = l->complex; - } - break; - - case OLSHR: - case OASHL: - case OASHR: - case OASLSHR: - case OASASHL: - case OASASHR: - if(r->complex >= l->complex) { - n->complex = l->complex + 2; - if(r->complex > n->complex) - n->complex = r->complex; - } else { - n->complex = r->complex + 2; - if(l->complex > n->complex) - n->complex = l->complex; - } - break; - case OADD: case OXOR: case OAND: case OOR: + case OEQ: + case ONE: /* * immediate operators, make const on right */ @@ -373,63 +263,5 @@ n->right = l; } break; - - case OEQ: - case ONE: - case OLE: - case OLT: - case OGE: - case OGT: - case OHI: - case OHS: - case OLO: - case OLS: - /* - * compare operators, make const on left - */ - if(r->op == OCONST) { - n->left = r; - n->right = l; - n->op = invrel[relindex(n->op)]; - } - break; } } - -void -indx(Node *n) -{ - Node *l, *r; - - if(debug['x']) - prtree(n, "indx"); - - l = n->left; - r = n->right; - if(l->addable == 1 || l->addable == 13 || r->complex > l->complex) { - n->right = l; - n->left = r; - l = r; - r = n->right; - } - if(l->addable != 7) { - idx.regtree = l; - idx.scale = 1; - } else - if(l->right->addable == 20) { - idx.regtree = l->left; - idx.scale = 1 << l->right->vconst; - } else - if(l->left->addable == 20) { - idx.regtree = l->right; - idx.scale = 1 << l->left->vconst; - } else - diag(n, "bad index"); - - idx.basetree = r; - if(debug['x']) { - print("scale = %d\n", idx.scale); - prtree(idx.regtree, "index"); - prtree(idx.basetree, "base"); - } -} diff -r d8d00747375b sys/src/cmd/6c/swt.c --- a/sys/src/cmd/6c/swt.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/6c/swt.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,17 +1,54 @@ +// Inferno utils/5c/swt.c +// http://code.google.com/p/inferno-os/source/browse/utils/5c/swt.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 "gc.h" void -swit1(C1 *q, int nc, long def, Node *n) +swit1(C1 *q, int nc, int32 def, Node *n) { C1 *r; int i; + int32 v; Prog *sp; + if(nc >= 3) { + i = (q+nc-1)->val - (q+0)->val; + if(i > 0 && i < nc*2) + goto direct; + } if(nc < 5) { for(i=0; ival); - gcmp(OEQ, n, q->val); + print("case = %.8ux\n", q->val); + gopcode(OEQ, nodconst(q->val), n, Z); patch(p, q->label); q++; } @@ -19,28 +56,53 @@ patch(p, def); return; } + i = nc / 2; r = q+i; if(debug['W']) - print("case > %.8llux\n", r->val); - gcmp(OGT, n, r->val); + print("case > %.8ux\n", r->val); + gopcode(OGT, nodconst(r->val), n, Z); sp = p; - gbranch(OGOTO); - p->as = AJEQ; + gopcode(OEQ, nodconst(r->val), n, Z); /* just gen the B.EQ */ patch(p, r->label); swit1(q, i, def, n); if(debug['W']) - print("case < %.8llux\n", r->val); + print("case < %.8ux\n", r->val); patch(sp, pc); swit1(r+1, nc-i-1, def, n); + return; + +direct: + v = q->val; + if(v != 0) + gopcode(OSUB, nodconst(v), Z, n); + gopcode(OCASE, nodconst((q+nc-1)->val - v), n, Z); + patch(p, def); + for(i=0; ival); + while(q->val != v) { + nextpc(); + p->as = ABCASE; + patch(p, def); + v++; + } + nextpc(); + p->as = ABCASE; + patch(p, q->label); + q++; + v++; + } + gbranch(OGOTO); /* so that regopt() won't be confused */ + patch(p, def); } void bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn) { int sh; - long v; + int32 v; Node *l; /* @@ -53,48 +115,54 @@ regalloc(n1, l, nn); reglcgen(n2, l, Z); regalloc(n3, l, Z); - gmove(n2, n3); - gmove(n3, n1); + gopcode(OAS, n2, Z, n3); + gopcode(OAS, n3, Z, n1); } else { regalloc(n1, l, nn); cgen(l, n1); } if(b->type->shift == 0 && typeu[b->type->etype]) { v = ~0 + (1L << b->type->nbits); - gopcode(OAND, tfield, nodconst(v), n1); + gopcode(OAND, nodconst(v), Z, n1); } else { sh = 32 - b->type->shift - b->type->nbits; if(sh > 0) - gopcode(OASHL, tfield, nodconst(sh), n1); + gopcode(OASHL, nodconst(sh), Z, n1); sh += b->type->shift; if(sh > 0) if(typeu[b->type->etype]) - gopcode(OLSHR, tfield, nodconst(sh), n1); + gopcode(OLSHR, nodconst(sh), Z, n1); else - gopcode(OASHR, tfield, nodconst(sh), n1); + gopcode(OASHR, nodconst(sh), Z, n1); } } void bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn) { - long v; - Node nod; + int32 v; + Node nod, *l; int sh; - regalloc(&nod, b->left, Z); + /* + * n1 has adjusted/masked value + * n2 has address of cell + * n3 has contents of cell + */ + l = b->left; + regalloc(&nod, l, Z); v = ~0 + (1L << b->type->nbits); - gopcode(OAND, types[TLONG], nodconst(v), n1); - gmove(n1, &nod); + gopcode(OAND, nodconst(v), Z, n1); + gopcode(OAS, n1, Z, &nod); if(nn != Z) - gmove(n1, nn); + gopcode(OAS, n1, Z, nn); sh = b->type->shift; if(sh > 0) - gopcode(OASHL, types[TLONG], nodconst(sh), &nod); + gopcode(OASHL, nodconst(sh), Z, &nod); v <<= sh; - gopcode(OAND, types[TLONG], nodconst(~v), n3); - gopcode(OOR, types[TLONG], n3, &nod); - gmove(&nod, n2); + gopcode(OAND, nodconst(~v), Z, n3); + gopcode(OOR, n3, Z, &nod); + gopcode(OAS, &nod, Z, n2); regfree(&nod); regfree(n1); @@ -102,10 +170,10 @@ regfree(n3); } -long -outstring(char *s, long n) +int32 +outstring(char *s, int32 n) { - long r; + int32 r; if(suppress) return nstring; @@ -117,7 +185,7 @@ if(mnstring >= NSNAME) { gpseudo(ADATA, symstring, nodconst(0L)); p->from.offset += nstring - NSNAME; - p->from.scale = NSNAME; + p->reg = NSNAME; p->to.type = D_SCONST; memmove(p->to.sval, string, NSNAME); mnstring = 0; @@ -127,61 +195,172 @@ return r; } +int +mulcon(Node *n, Node *nn) +{ + Node *l, *r, nod1, nod2; + Multab *m; + int32 v, vs; + int o; + char code[sizeof(m->code)+2], *p; + + if(typefd[n->type->etype]) + return 0; + l = n->left; + r = n->right; + if(l->op == OCONST) { + l = r; + r = n->left; + } + if(r->op != OCONST) + return 0; + v = convvtox(r->vconst, n->type->etype); + if(v != r->vconst) { + if(debug['M']) + print("%L multiply conv: %lld\n", n->lineno, r->vconst); + return 0; + } + m = mulcon0(v); + if(!m) { + if(debug['M']) + print("%L multiply table: %lld\n", n->lineno, r->vconst); + return 0; + } + if(debug['M'] && debug['v']) + print("%L multiply: %d\n", n->lineno, v); + + memmove(code, m->code, sizeof(m->code)); + code[sizeof(m->code)] = 0; + + p = code; + if(p[1] == 'i') + p += 2; + regalloc(&nod1, n, nn); + cgen(l, &nod1); + vs = v; + regalloc(&nod2, n, Z); + +loop: + switch(*p) { + case 0: + regfree(&nod2); + if(vs < 0) { + gopcode(OAS, &nod1, Z, &nod1); + gopcode(OSUB, &nod1, nodconst(0), nn); + } else + gopcode(OAS, &nod1, Z, nn); + regfree(&nod1); + return 1; + case '+': + o = OADD; + goto addsub; + case '-': + o = OSUB; + addsub: /* number is r,n,l */ + v = p[1] - '0'; + r = &nod1; + if(v&4) + r = &nod2; + n = &nod1; + if(v&2) + n = &nod2; + l = &nod1; + if(v&1) + l = &nod2; + gopcode(o, l, n, r); + break; + default: /* op is shiftcount, number is r,l */ + v = p[1] - '0'; + r = &nod1; + if(v&2) + r = &nod2; + l = &nod1; + if(v&1) + l = &nod2; + v = *p - 'a'; + if(v < 0 || v >= 32) { + diag(n, "mulcon unknown op: %c%c", p[0], p[1]); + break; + } + gopcode(OASHL, nodconst(v), l, r); + break; + } + p += 2; + goto loop; +} + void -sextern(Sym *s, Node *a, long o, long w) +sextern(Sym *s, Node *a, int32 o, int32 w) { - long e, lw; + int32 e, lw; for(e=0; efrom.offset += o+e; - p->from.scale = lw; + p->reg = lw; p->to.type = D_SCONST; memmove(p->to.sval, a->cstring+e, lw); } } void -gextern(Sym *s, Node *a, long o, long w) +gextern(Sym *s, Node *a, int32 o, int32 w) { - if(0 && a->op == OCONST && typev[a->type->etype]) { - gpseudo(ADATA, s, lo64(a)); + + if(a->op == OCONST && typev[a->type->etype]) { + if(isbigendian) + gpseudo(ADATA, s, nod32const(a->vconst>>32)); + else + gpseudo(ADATA, s, nod32const(a->vconst)); p->from.offset += o; - p->from.scale = 4; - gpseudo(ADATA, s, hi64(a)); + p->reg = 4; + if(isbigendian) + gpseudo(ADATA, s, nod32const(a->vconst)); + else + gpseudo(ADATA, s, nod32const(a->vconst>>32)); p->from.offset += o + 4; - p->from.scale = 4; + p->reg = 4; return; } gpseudo(ADATA, s, a); p->from.offset += o; - p->from.scale = w; - switch(p->to.type) { - default: - p->to.index = p->to.type; - p->to.type = D_ADDR; - case D_CONST: - case D_FCONST: - case D_ADDR: - break; - } + p->reg = w; + if(p->to.type == D_OREG) + p->to.type = D_CONST; } void zname(Biobuf*, Sym*, int); -void zaddr(Biobuf*, Adr*, int); +char* zaddr(char*, Adr*, int); +void zwrite(Biobuf*, Prog*, int, int); void outhist(Biobuf*); void +zwrite(Biobuf *b, Prog *p, int sf, int st) +{ + char bf[100], *bp; + + bf[0] = p->as; + bf[1] = p->scond; + bf[2] = p->reg; + bf[3] = p->lineno; + bf[4] = p->lineno>>8; + bf[5] = p->lineno>>16; + bf[6] = p->lineno>>24; + bp = zaddr(bf+7, &p->from, sf); + bp = zaddr(bp, &p->to, st); + Bwrite(b, bf, bp-bf); +} + +void outcode(void) { struct { Sym *sym; short type; } h[NSYM]; Prog *p; Sym *s; - int f, sf, st, t, sym; - Biobuf b; + int sf, st, t, sym; if(debug['S']) { for(p = firstp; p != P; p = p->link) @@ -193,14 +372,25 @@ pc++; } } - f = open(outfile, OWRITE); - if(f < 0) { - diag(Z, "cannot open %s", outfile); - return; + + Bprint(&outbuf, "go object %s %s %s\n", getgoos(), thestring, getgoversion()); + if(ndynimp > 0 || ndynexp > 0) { + int i; + + Bprint(&outbuf, "\n"); + Bprint(&outbuf, "$$ // exports\n\n"); + Bprint(&outbuf, "$$ // local types\n\n"); + Bprint(&outbuf, "$$ // dynimport\n"); + for(i=0; isym; if(sf < 0 || sf >= NSYM) sf = 0; - t = p->from.type; - if(t == D_ADDR) - t = p->from.index; + t = p->from.name; if(h[sf].type == t) if(h[sf].sym == s) break; s->sym = sym; - zname(&b, s, t); + zname(&outbuf, s, t); h[sym].sym = s; h[sym].type = t; sf = sym; @@ -236,14 +424,12 @@ st = s->sym; if(st < 0 || st >= NSYM) st = 0; - t = p->to.type; - if(t == D_ADDR) - t = p->to.index; + t = p->to.name; if(h[st].type == t) if(h[st].sym == s) break; s->sym = sym; - zname(&b, s, t); + zname(&outbuf, s, t); h[sym].sym = s; h[sym].type = t; st = sym; @@ -254,17 +440,8 @@ goto jackpot; break; } - Bputc(&b, p->as); - Bputc(&b, p->as>>8); - Bputc(&b, p->lineno); - Bputc(&b, p->lineno>>8); - Bputc(&b, p->lineno>>16); - Bputc(&b, p->lineno>>24); - zaddr(&b, &p->from, sf); - zaddr(&b, &p->to, st); + zwrite(&outbuf, p, sf, st); } - Bflush(&b); - close(f); firstp = P; lastp = P; } @@ -283,17 +460,13 @@ for(h = hist; h != H; h = h->link) { p = h->name; op = 0; - /* on windows skip drive specifier in pathname */ if(systemtype(Windows) && p && p[1] == ':'){ - p += 2; - c = *p; - } - if(p && p[0] != c && h->offset == 0 && pathname){ - /* on windows skip drive specifier in pathname */ + c = p[2]; + } else if(p && p[0] != c && h->offset == 0 && pathname){ if(systemtype(Windows) && pathname[1] == ':') { op = p; - p = pathname+2; - c = *p; + p = pathname; + c = p[2]; } else if(pathname[0] == c){ op = p; p = pathname; @@ -314,7 +487,6 @@ } if(n) { Bputc(b, ANAME); - Bputc(b, ANAME>>8); Bputc(b, D_FILE); Bputc(b, 1); Bputc(b, '<'); @@ -333,131 +505,106 @@ if(h->offset) pg.to.type = D_CONST; - Bputc(b, pg.as); - Bputc(b, pg.as>>8); - Bputc(b, pg.lineno); - Bputc(b, pg.lineno>>8); - Bputc(b, pg.lineno>>16); - Bputc(b, pg.lineno>>24); - zaddr(b, &pg.from, 0); - zaddr(b, &pg.to, 0); + zwrite(b, &pg, 0, 0); } } void zname(Biobuf *b, Sym *s, int t) { - char *n; - ulong sig; + char *n, bf[7]; + uint32 sig; + n = s->name; if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){ sig = sign(s); - Bputc(b, ASIGNAME); - Bputc(b, ASIGNAME>>8); - Bputc(b, sig); - Bputc(b, sig>>8); - Bputc(b, sig>>16); - Bputc(b, sig>>24); + bf[0] = ASIGNAME; + bf[1] = sig; + bf[2] = sig>>8; + bf[3] = sig>>16; + bf[4] = sig>>24; + bf[5] = t; + bf[6] = s->sym; + Bwrite(b, bf, 7); s->sig = SIGDONE; } else{ - Bputc(b, ANAME); /* as */ - Bputc(b, ANAME>>8); /* as */ + bf[0] = ANAME; + bf[1] = t; /* type */ + bf[2] = s->sym; /* sym */ + Bwrite(b, bf, 3); } - Bputc(b, t); /* type */ - Bputc(b, s->sym); /* sym */ - n = s->name; - while(*n) { - Bputc(b, *n); - n++; - } - Bputc(b, 0); + Bwrite(b, n, strlen(n)+1); } -void -zaddr(Biobuf *b, Adr *a, int s) +char* +zaddr(char *bp, Adr *a, int s) { - long l; - int i, t; - char *n; + int32 l; Ieee e; - t = 0; - if(a->index != D_NONE || a->scale != 0) - t |= T_INDEX; - if(s != 0) - t |= T_SYM; - + bp[0] = a->type; + bp[1] = a->reg; + bp[2] = s; + bp[3] = a->name; + bp += 4; switch(a->type) { default: - t |= T_TYPE; + diag(Z, "unknown type %d in zaddr", a->type); + case D_NONE: - if(a->offset != 0) { - t |= T_OFFSET; - l = a->offset; - if((vlong)l != a->offset) - t |= T_64; - } + case D_REG: + case D_FREG: + case D_PSR: break; + + case D_CONST2: + l = a->offset2; + bp[0] = l; + bp[1] = l>>8; + bp[2] = l>>16; + bp[3] = l>>24; + bp += 4; // fall through + case D_OREG: + case D_CONST: + case D_BRANCH: + case D_SHIFT: + l = a->offset; + bp[0] = l; + bp[1] = l>>8; + bp[2] = l>>16; + bp[3] = l>>24; + bp += 4; + break; + + case D_SCONST: + memmove(bp, a->sval, NSNAME); + bp += NSNAME; + break; + case D_FCONST: - t |= T_FCONST; - break; - case D_SCONST: - t |= T_SCONST; + ieeedtod(&e, a->dval); + l = e.l; + bp[0] = l; + bp[1] = l>>8; + bp[2] = l>>16; + bp[3] = l>>24; + bp += 4; + l = e.h; + bp[0] = l; + bp[1] = l>>8; + bp[2] = l>>16; + bp[3] = l>>24; + bp += 4; break; } - Bputc(b, t); - - if(t & T_INDEX) { /* implies index, scale */ - Bputc(b, a->index); - Bputc(b, a->scale); - } - if(t & T_OFFSET) { /* implies offset */ - l = a->offset; - Bputc(b, l); - Bputc(b, l>>8); - Bputc(b, l>>16); - Bputc(b, l>>24); - if(t & T_64) { - l = a->offset>>32; - Bputc(b, l); - Bputc(b, l>>8); - Bputc(b, l>>16); - Bputc(b, l>>24); - } - } - if(t & T_SYM) /* implies sym */ - Bputc(b, s); - if(t & T_FCONST) { - ieeedtod(&e, a->dval); - l = e.l; - Bputc(b, l); - Bputc(b, l>>8); - Bputc(b, l>>16); - Bputc(b, l>>24); - l = e.h; - Bputc(b, l); - Bputc(b, l>>8); - Bputc(b, l>>16); - Bputc(b, l>>24); - return; - } - if(t & T_SCONST) { - n = a->sval; - for(i=0; itype); + return bp; } -long -align(long i, Type *t, int op) +int32 +align(int32 i, Type *t, int op, int32 *maxalign) { - long o; + int32 o; Type *v; int w; @@ -469,7 +616,9 @@ break; case Asu2: /* padding at end of a struct */ - w = SZ_VLONG; + w = *maxalign; + if(w < 1) + w = 1; if(packflg) w = packflg; break; @@ -477,10 +626,16 @@ case Ael1: /* initial align of struct element */ for(v=t; v->etype==TARRAY; v=v->link) ; - w = ewidth[v->etype]; - if(w <= 0 || w >= SZ_VLONG) - w = SZ_VLONG; - if(packflg) + if(v->etype == TSTRUCT || v->etype == TUNION) + w = v->align; + else { + w = ewidth[v->etype]; + if(w == 8) + w = 4; + } + if(w < 1 || w > SZ_LONG) + fatal(Z, "align"); + if(packflg) w = packflg; break; @@ -489,16 +644,16 @@ break; case Aarg0: /* initial passbyptr argument in arg list */ - if(typesu[t->etype]) { - o = align(o, types[TIND], Aarg1); - o = align(o, types[TIND], Aarg2); + if(typesuv[t->etype]) { + o = align(o, types[TIND], Aarg1, nil); + o = align(o, types[TIND], Aarg2, nil); } break; case Aarg1: /* initial align of parameter */ w = ewidth[t->etype]; - if(w <= 0 || w >= SZ_VLONG) { - w = SZ_VLONG; + if(w <= 0 || w >= SZ_LONG) { + w = SZ_LONG; break; } w = 1; /* little endian no adjustment */ @@ -506,25 +661,30 @@ case Aarg2: /* width of a parameter */ o += t->width; - w = SZ_VLONG; + w = t->width; + if(w > SZ_LONG) + w = SZ_LONG; break; - case Aaut3: /* total allign of automatic */ - o = align(o, t, Ael1); - o = align(o, t, Ael2); + case Aaut3: /* total align of automatic */ + o = align(o, t, Ael2, nil); + o = align(o, t, Ael1, nil); + w = SZ_LONG; /* because of a pun in cc/dcl.c:contig() */ break; } - o = round(o, w); + o = xround(o, w); + if(maxalign != nil && *maxalign < w) + *maxalign = w; if(debug['A']) - print("align %s %ld %T = %ld\n", bnames[op], i, t, o); + print("align %s %d %T = %d\n", bnames[op], i, t, o); return o; } -long -maxround(long max, long v) +int32 +maxround(int32 max, int32 v) { - v += SZ_VLONG-1; + v = xround(v, SZ_LONG); if(v > max) - max = round(v, SZ_VLONG); + return v; return max; } diff -r d8d00747375b sys/src/cmd/6c/sys.c --- a/sys/src/cmd/6c/sys.c Thu Sep 29 03:00:00 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,106 +0,0 @@ -#include -#include -#include "/sys/src/libc/9syscall/sys.h" - -vlong _sysargs[6*4]; -vlong _callsys(void); - -/* - * syscalls - */ - -int -getpid(void) -{ - _sysargs[0] = -1; - return _callsys(); -} - -long -pread(int fd, void *a, long n, vlong) -{ - _sysargs[0] = PREAD; - _sysargs[1] = fd; - _sysargs[2] = (vlong)a; - _sysargs[3] = n; - return _callsys(); -} - -long -pwrite(int fd, void *a, long n, vlong) -{ - _sysargs[0] = PWRITE; - _sysargs[1] = fd; - _sysargs[2] = (vlong)a; - _sysargs[3] = n; - return _callsys(); -} - -int -close(int fd) -{ - _sysargs[0] = CLOSE; - _sysargs[1] = fd; - return _callsys(); -} - -int -open(char *name, int mode) -{ - _sysargs[0] = OPEN; - _sysargs[1] = (vlong)name; - _sysargs[2] = mode; - return _callsys(); -} - -int -create(char *f, int mode, ulong perm) -{ - _sysargs[0] = CREATE; - _sysargs[1] = (vlong)f; - _sysargs[2] = mode; - _sysargs[3] = perm; - return _callsys(); -} - -void -_exits(char *s) -{ - _sysargs[0] = EXITS; - _sysargs[1] = s!=nil? strlen(s): 0; - _callsys(); -} - -int -dup(int f, int t) -{ - _sysargs[0] = DUP; - _sysargs[1] = f; - _sysargs[2] = t; - return _callsys(); -} - -int -errstr(char *buf, uint n) -{ - _sysargs[0] = ERRSTR; - _sysargs[1] = (vlong)buf; - _sysargs[2] = n; - return _callsys(); -} - -int -brk_(void *a) -{ - _sysargs[0] = BRK_; - _sysargs[1] = (vlong)a; - return _callsys(); -} - -void* -sbrk(ulong n) -{ - _sysargs[0] = -2; - _sysargs[1] = n; - return (void*)_callsys(); -} diff -r d8d00747375b sys/src/cmd/6c/txt.c --- a/sys/src/cmd/6c/txt.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/6c/txt.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,13 +1,43 @@ +// Inferno utils/5c/txt.c +// http://code.google.com/p/inferno-os/source/browse/utils/5c/txt.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 "gc.h" void ginit(void) { - int i; Type *t; - thechar = '6'; - thestring = "amd64"; + thechar = '5'; + thestring = "arm"; exregoffset = REGEXT; exfregoffset = FREGEXT; listinit(); @@ -20,32 +50,23 @@ cases = C; firstp = P; lastp = P; - tfield = types[TINT]; - - typeword = typechlvp; - typecmplx = typesu; - - /* TO DO */ - memmove(typechlpv, typechlp, sizeof(typechlpv)); - typechlpv[TVLONG] = 1; - typechlpv[TUVLONG] = 1; + tfield = types[TLONG]; zprog.link = P; zprog.as = AGOK; + zprog.reg = NREG; zprog.from.type = D_NONE; - zprog.from.index = D_NONE; - zprog.from.scale = 0; + zprog.from.name = D_NONE; + zprog.from.reg = NREG; zprog.to = zprog.from; + zprog.scond = 0xE; - lregnode.op = OREGISTER; - lregnode.class = CEXREG; - lregnode.reg = REGTMP; - lregnode.complex = 0; - lregnode.addable = 11; - lregnode.type = types[TLONG]; - - qregnode = lregnode; - qregnode.type = types[TVLONG]; + regnode.op = OREGISTER; + regnode.class = CEXREG; + regnode.reg = REGTMP; + regnode.complex = 0; + regnode.addable = 11; + regnode.type = types[TLONG]; constnode.op = OCONST; constnode.class = CXXX; @@ -53,9 +74,6 @@ constnode.addable = 20; constnode.type = types[TLONG]; - vconstnode = constnode; - vconstnode.type = types[TVLONG]; - fconstnode.op = OCONST; fconstnode.class = CXXX; fconstnode.complex = 0; @@ -90,16 +108,9 @@ nodret = new(OIND, nodret, Z); complex(nodret); - if(0) - com64init(); + com64init(); - for(i=0; i= D_AX && i <= D_R15 && i != D_SP) - reg[i] = 0; - if(i >= D_X0 && i <= D_X7) - reg[i] = 0; - } + memset(reg, 0, sizeof(reg)); } void @@ -108,13 +119,12 @@ int i; Sym *s; - reg[D_SP]--; - for(i=D_AX; i<=D_R15; i++) + for(i=0; itype->width = nstring; @@ -156,7 +166,7 @@ void gargs(Node *n, Node *tn1, Node *tn2) { - long regs; + int32 regs; Node fnxargs[20], *fnxp; regs = cursafe; @@ -171,18 +181,6 @@ cursafe = regs; } -int -nareg(void) -{ - int i, n; - - n = 0; - for(i=D_AX; i<=D_R15; i++) - if(reg[i] == 0) - n++; - return n; -} - void garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp) { @@ -208,7 +206,7 @@ } return; } - if(typesu[n->type->etype]) { + if(typesuv[n->type->etype]) { regaalloc(tn2, n); if(n->complex >= FNX) { sugen(*fnxp, tn2, n->type->width); @@ -217,7 +215,7 @@ sugen(n, tn2, n->type->width); return; } - if(REGARG && curarg == 0 && typechlpv[n->type->etype]) { + if(REGARG >= 0 && curarg == 0 && typechlp[n->type->etype]) { regaalloc1(tn1, n); if(n->complex >= FNX) { cgen(*fnxp, tn1); @@ -226,11 +224,6 @@ cgen(n, tn1); return; } - if(vconst(n) == 0) { - regaalloc(tn2, n); - gmove(n, tn2); - return; - } regalloc(tn1, n, Z); if(n->complex >= FNX) { cgen(*fnxp, tn1); @@ -238,23 +231,21 @@ } else cgen(n, tn1); regaalloc(tn2, n); - gmove(tn1, tn2); + gopcode(OAS, tn1, Z, tn2); regfree(tn1); } Node* -nodgconst(vlong v, Type *t) +nodconst(int32 v) { - if(!typev[t->etype]) - return nodconst((long)v); - vconstnode.vconst = v; - return &vconstnode; + constnode.vconst = v; + return &constnode; } Node* -nodconst(long v) +nod32const(vlong v) { - constnode.vconst = v; + constnode.vconst = v & MASK(32); return &constnode; } @@ -265,40 +256,13 @@ return &fconstnode; } -int -isreg(Node *n, int r) +void +nodreg(Node *n, Node *nn, int reg) { - - if(n->op == OREGISTER) - if(n->reg == r) - return 1; - return 0; -} - -int -nodreg(Node *n, Node *nn, int r) -{ - int et; - - *n = qregnode; - n->reg = r; - if(nn != Z){ - et = nn->type->etype; - if(!typefd[et] && nn->type->width <= SZ_LONG && 0) - n->type = typeu[et]? types[TUINT]: types[TINT]; - else - n->type = nn->type; -//print("nodreg %s [%s]\n", tnames[et], tnames[n->type->etype]); - n->lineno = nn->lineno; - } - if(reg[r] == 0) - return 0; - if(nn != Z) { - if(nn->op == OREGISTER) - if(nn->reg == r) - return 0; - } - return 1; + *n = regnode; + n->reg = reg; + n->type = nn->type; + n->lineno = nn->lineno; } void @@ -308,11 +272,23 @@ r = REGRET; if(typefd[nn->type->etype]) - r = FREGRET; + r = FREGRET+NREG; nodreg(n, nn, r); reg[r]++; } +int +tmpreg(void) +{ + int i; + + for(i=REGRET+1; iop == OREGISTER) { i = o->reg; - if(i >= D_AX && i <= D_R15) + if(i >= 0 && i < NREG) goto out; } - for(i=D_AX; i<=D_R15; i++) + for(i=REGRET+1; i<=REGEXT-2; i++) if(reg[i] == 0) goto out; diag(tn, "out of fixed registers"); @@ -343,23 +317,24 @@ case TFLOAT: case TDOUBLE: + case TVLONG: if(o != Z && o->op == OREGISTER) { i = o->reg; - if(i >= D_X0 && i <= D_X7) + if(i >= NREG && i < NREG+NFREG) goto out; } - for(i=D_X0; i<=D_X7; i++) + for(i=NREG; itype); err: - i = 0; + nodreg(n, tn, 0); + return; out: - if(i) - reg[i]++; + reg[i]++; nodreg(n, tn, i); } @@ -389,13 +364,13 @@ reg[i]--; return; err: - diag(n, "error in regfree: %R", i); + diag(n, "error in regfree: %d", i); } void regsalloc(Node *n, Node *nn) { - cursafe = align(cursafe, nn->type, Aaut3); + cursafe = align(cursafe, nn->type, Aaut3, nil); maxargsafe = maxround(maxargsafe, cursafe+curarg); *n = *nodsafe; n->xoffset = -(stkoff + cursafe); @@ -407,24 +382,28 @@ void regaalloc1(Node *n, Node *nn) { + if(REGARG < 0) { + fatal(n, "regaalloc1 and REGARG<0"); + return; + } nodreg(n, nn, REGARG); reg[REGARG]++; - curarg = align(curarg, nn->type, Aarg1); - curarg = align(curarg, nn->type, Aarg2); + curarg = align(curarg, nn->type, Aarg1, nil); + curarg = align(curarg, nn->type, Aarg2, nil); maxargsafe = maxround(maxargsafe, cursafe+curarg); } void regaalloc(Node *n, Node *nn) { - curarg = align(curarg, nn->type, Aarg1); + curarg = align(curarg, nn->type, Aarg1, nil); *n = *nn; n->op = OINDREG; n->reg = REGSP; - n->xoffset = curarg; + n->xoffset = curarg + SZ_LONG; n->complex = 0; n->addable = 20; - curarg = align(curarg, nn->type, Aarg2); + curarg = align(curarg, nn->type, Aarg2, nil); maxargsafe = maxround(maxargsafe, cursafe+curarg); } @@ -441,9 +420,29 @@ } void +raddr(Node *n, Prog *p) +{ + Adr a; + + naddr(n, &a); + if(R0ISZERO && a.type == D_CONST && a.offset == 0) { + a.type = D_REG; + a.reg = 0; + } + if(a.type != D_REG && a.type != D_FREG) { + if(n) + diag(n, "bad in raddr: %O", n->op); + else + diag(n, "bad in raddr: "); + p->reg = NREG; + } else + p->reg = a.reg; +} + +void naddr(Node *n, Adr *a) { - long v; + int32 v; a->type = D_NONE; if(n == Z) @@ -451,116 +450,90 @@ switch(n->op) { default: bad: - diag(n, "bad in naddr: %O %D", n->op, a); + diag(n, "bad in naddr: %O", n->op); break; case OREGISTER: - a->type = n->reg; + a->type = D_REG; a->sym = S; + a->reg = n->reg; + if(a->reg >= NREG) { + a->type = D_FREG; + a->reg -= NREG; + } break; - case OIND: naddr(n->left, a); - if(a->type >= D_AX && a->type <= D_R15) - a->type += D_INDIR; - else - if(a->type == D_CONST) - a->type = D_NONE+D_INDIR; - else - if(a->type == D_ADDR) { - a->type = a->index; - a->index = D_NONE; - } else - goto bad; - break; - - case OINDEX: - a->type = idx.ptr; - if(n->left->op == OADDR || n->left->op == OCONST) - naddr(n->left, a); - if(a->type >= D_AX && a->type <= D_R15) - a->type += D_INDIR; - else - if(a->type == D_CONST) - a->type = D_NONE+D_INDIR; - else - if(a->type == D_ADDR) { - a->type = a->index; - a->index = D_NONE; - } else - goto bad; - a->index = idx.reg; - a->scale = n->scale; - a->offset += n->xoffset; - break; + if(a->type == D_REG) { + a->type = D_OREG; + break; + } + if(a->type == D_CONST) { + a->type = D_OREG; + break; + } + goto bad; case OINDREG: - a->type = n->reg+D_INDIR; + a->type = D_OREG; a->sym = S; a->offset = n->xoffset; + a->reg = n->reg; break; case ONAME: a->etype = n->etype; - a->type = D_STATIC; + a->type = D_OREG; + a->name = D_STATIC; a->sym = n->sym; a->offset = n->xoffset; if(n->class == CSTATIC) break; if(n->class == CEXTERN || n->class == CGLOBL) { - a->type = D_EXTERN; + a->name = D_EXTERN; break; } if(n->class == CAUTO) { - a->type = D_AUTO; + a->name = D_AUTO; break; } if(n->class == CPARAM) { - a->type = D_PARAM; + a->name = D_PARAM; break; } goto bad; case OCONST: + a->sym = S; + a->reg = NREG; if(typefd[n->type->etype]) { a->type = D_FCONST; a->dval = n->fconst; - break; + } else { + a->type = D_CONST; + a->offset = n->vconst; } - a->sym = S; - a->type = D_CONST; - if(typev[n->type->etype] || n->type->etype == TIND) - a->offset = n->vconst; - else - a->offset = convvtox(n->vconst, typeu[n->type->etype]? TULONG: TLONG); break; case OADDR: naddr(n->left, a); - if(a->type >= D_INDIR) { - a->type -= D_INDIR; + if(a->type == D_OREG) { + a->type = D_CONST; break; } - if(a->type == D_EXTERN || a->type == D_STATIC || - a->type == D_AUTO || a->type == D_PARAM) - if(a->index == D_NONE) { - a->index = a->type; - a->type = D_ADDR; - break; - } goto bad; case OADD: - if(n->right->op == OCONST) { - v = n->right->vconst; + if(n->left->op == OCONST) { naddr(n->left, a); - } else - if(n->left->op == OCONST) { - v = n->left->vconst; + v = a->offset; naddr(n->right, a); - } else - goto bad; + } else { + naddr(n->right, a); + v = a->offset; + naddr(n->left, a); + } a->offset += v; break; @@ -568,586 +541,381 @@ } void -gcmp(int op, Node *n, vlong val) +fop(int as, int f1, int f2, Node *t) { - Node *cn, nod; + Node nod1, nod2, nod3; - cn = nodgconst(val, n->type); - if(!immconst(cn)){ - regalloc(&nod, n, Z); - gmove(cn, &nod); - gopcode(op, n->type, n, &nod); - regfree(&nod); - }else - gopcode(op, n->type, n, cn); + nodreg(&nod1, t, NREG+f1); + nodreg(&nod2, t, NREG+f2); + regalloc(&nod3, t, t); + gopcode(as, &nod1, &nod2, &nod3); + gmove(&nod3, t); + regfree(&nod3); } -#define CASE(a,b) ((a<<8)|(b<<0)) +void +gmovm(Node *f, Node *t, int w) +{ + gins(AMOVM, f, t); + p->scond |= C_UBIT; + if(w) + p->scond |= C_WBIT; +} void gmove(Node *f, Node *t) { - int ft, tt, t64, a; - Node nod, nod1, nod2, nod3; - Prog *p1, *p2; + int ft, tt, a; + Node nod, nod1; + Prog *p1; ft = f->type->etype; tt = t->type->etype; - t64 = tt == TVLONG || tt == TUVLONG || tt == TIND; - if(debug['M']) - print("gop: %O %O[%s],%O[%s]\n", OAS, - f->op, tnames[ft], t->op, tnames[tt]); - if(typefd[ft] && f->op == OCONST) { - /* TO DO: pick up special constants, possibly preloaded */ - if(f->fconst == 0.0){ + + if(ft == TDOUBLE && f->op == OCONST) { + } + if(ft == TFLOAT && f->op == OCONST) { + } + + /* + * a load -- + * put it into a register then + * worry what to do with it. + */ + if(f->op == ONAME || f->op == OINDREG || f->op == OIND) { + switch(ft) { + default: + a = AMOVW; + break; + case TFLOAT: + a = AMOVF; + break; + case TDOUBLE: + a = AMOVD; + break; + case TCHAR: + a = AMOVB; + break; + case TUCHAR: + a = AMOVBU; + break; + case TSHORT: + a = AMOVH; + break; + case TUSHORT: + a = AMOVHU; + break; + } + if(typechlp[ft] && typeilp[tt]) regalloc(&nod, t, t); - gins(AXORPD, &nod, &nod); - gmove(&nod, t); - regfree(&nod); - return; - } - } -/* - * load - */ - if(f->op == ONAME || f->op == OINDREG || - f->op == OIND || f->op == OINDEX) - switch(ft) { - case TCHAR: - a = AMOVBLSX; - if(t64) - a = AMOVBQSX; - goto ld; - case TUCHAR: - a = AMOVBLZX; - if(t64) - a = AMOVBQZX; - goto ld; - case TSHORT: - a = AMOVWLSX; - if(t64) - a = AMOVWQSX; - goto ld; - case TUSHORT: - a = AMOVWLZX; - if(t64) - a = AMOVWQZX; - goto ld; - case TINT: - case TLONG: - if(typefd[tt]) { - regalloc(&nod, t, t); - if(tt == TDOUBLE) - a = ACVTSL2SD; - else - a = ACVTSL2SS; - gins(a, f, &nod); - gmove(&nod, t); - regfree(&nod); - return; - } - a = AMOVL; - if(t64) - a = AMOVLQSX; - goto ld; - case TUINT: - case TULONG: - a = AMOVL; - if(t64) - a = AMOVLQZX; /* could probably use plain MOVL */ - goto ld; - case TVLONG: - if(typefd[tt]) { - regalloc(&nod, t, t); - if(tt == TDOUBLE) - a = ACVTSQ2SD; - else - a = ACVTSQ2SS; - gins(a, f, &nod); - gmove(&nod, t); - regfree(&nod); - return; - } - case TUVLONG: - a = AMOVQ; - goto ld; - case TIND: - a = AMOVQ; - - ld: - regalloc(&nod, f, t); - nod.type = t64? types[TVLONG]: types[TINT]; - gins(a, f, &nod); - gmove(&nod, t); - regfree(&nod); - return; - - case TFLOAT: - a = AMOVSS; - goto fld; - case TDOUBLE: - a = AMOVSD; - fld: - regalloc(&nod, f, t); - if(tt != TDOUBLE && tt != TFLOAT){ /* TO DO: why is this here */ - prtree(f, "odd tree"); - nod.type = t64? types[TVLONG]: types[TINT]; - } + else + regalloc(&nod, f, t); gins(a, f, &nod); gmove(&nod, t); regfree(&nod); return; } -/* - * store - */ - if(t->op == ONAME || t->op == OINDREG || - t->op == OIND || t->op == OINDEX) - switch(tt) { - case TCHAR: - case TUCHAR: - a = AMOVB; goto st; - case TSHORT: - case TUSHORT: - a = AMOVW; goto st; - case TINT: - case TUINT: - case TLONG: - case TULONG: - a = AMOVL; goto st; - case TVLONG: - case TUVLONG: - case TIND: - a = AMOVQ; goto st; - - st: - if(f->op == OCONST) { - gins(a, f, t); - return; + /* + * a store -- + * put it into a register then + * store it. + */ + if(t->op == ONAME || t->op == OINDREG || t->op == OIND) { + switch(tt) { + default: + a = AMOVW; + break; + case TUCHAR: + a = AMOVBU; + break; + case TCHAR: + a = AMOVB; + break; + case TUSHORT: + a = AMOVHU; + break; + case TSHORT: + a = AMOVH; + break; + case TFLOAT: + a = AMOVF; + break; + case TVLONG: + case TDOUBLE: + a = AMOVD; + break; } - fst: - regalloc(&nod, t, f); + if(ft == tt) + regalloc(&nod, t, f); + else + regalloc(&nod, t, Z); gmove(f, &nod); gins(a, &nod, t); regfree(&nod); return; - - case TFLOAT: - a = AMOVSS; - goto fst; - case TDOUBLE: - a = AMOVSD; - goto fst; } -/* - * convert - */ - switch(CASE(ft,tt)) { - default: -/* - * integer to integer - ******** - a = AGOK; break; - - case CASE( TCHAR, TCHAR): - case CASE( TUCHAR, TCHAR): - case CASE( TSHORT, TCHAR): - case CASE( TUSHORT,TCHAR): - case CASE( TINT, TCHAR): - case CASE( TUINT, TCHAR): - case CASE( TLONG, TCHAR): - case CASE( TULONG, TCHAR): - case CASE( TIND, TCHAR): - - case CASE( TCHAR, TUCHAR): - case CASE( TUCHAR, TUCHAR): - case CASE( TSHORT, TUCHAR): - case CASE( TUSHORT,TUCHAR): - case CASE( TINT, TUCHAR): - case CASE( TUINT, TUCHAR): - case CASE( TLONG, TUCHAR): - case CASE( TULONG, TUCHAR): - case CASE( TIND, TUCHAR): - - case CASE( TSHORT, TSHORT): - case CASE( TUSHORT,TSHORT): - case CASE( TINT, TSHORT): - case CASE( TUINT, TSHORT): - case CASE( TLONG, TSHORT): - case CASE( TULONG, TSHORT): - case CASE( TIND, TSHORT): - - case CASE( TSHORT, TUSHORT): - case CASE( TUSHORT,TUSHORT): - case CASE( TINT, TUSHORT): - case CASE( TUINT, TUSHORT): - case CASE( TLONG, TUSHORT): - case CASE( TULONG, TUSHORT): - case CASE( TIND, TUSHORT): - - case CASE( TINT, TINT): - case CASE( TUINT, TINT): - case CASE( TLONG, TINT): - case CASE( TULONG, TINT): - case CASE( TIND, TINT): - - case CASE( TINT, TUINT): - case CASE( TUINT, TUINT): - case CASE( TLONG, TUINT): - case CASE( TULONG, TUINT): - case CASE( TIND, TUINT): - - case CASE( TUINT, TIND): - case CASE( TVLONG, TUINT): - case CASE( TVLONG, TULONG): - case CASE( TUVLONG, TUINT): - case CASE( TUVLONG, TULONG): - *****/ - a = AMOVL; - break; - - case CASE( TVLONG, TCHAR): - case CASE( TVLONG, TSHORT): - case CASE( TVLONG, TINT): - case CASE( TVLONG, TLONG): - case CASE( TUVLONG, TCHAR): - case CASE( TUVLONG, TSHORT): - case CASE( TUVLONG, TINT): - case CASE( TUVLONG, TLONG): - case CASE( TINT, TVLONG): - case CASE( TINT, TUVLONG): - case CASE( TLONG, TVLONG): - case CASE( TINT, TIND): - case CASE( TLONG, TIND): - a = AMOVLQSX; - if(f->op == OCONST) { - f->vconst &= (uvlong)0xffffffffU; - if(f->vconst & 0x80000000) - f->vconst |= (vlong)0xffffffff << 32; - a = AMOVQ; + /* + * type x type cross table + */ + a = AGOK; + switch(ft) { + case TDOUBLE: + case TVLONG: + case TFLOAT: + switch(tt) { + case TDOUBLE: + case TVLONG: + a = AMOVD; + if(ft == TFLOAT) + a = AMOVFD; + break; + case TFLOAT: + a = AMOVDF; + if(ft == TFLOAT) + a = AMOVF; + break; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + a = AMOVDW; + if(ft == TFLOAT) + a = AMOVFW; + break; + case TSHORT: + case TUSHORT: + case TCHAR: + case TUCHAR: + a = AMOVDW; + if(ft == TFLOAT) + a = AMOVFW; + break; } break; - - case CASE( TUINT, TIND): - case CASE( TUINT, TVLONG): - case CASE( TUINT, TUVLONG): - case CASE( TULONG, TVLONG): - case CASE( TULONG, TUVLONG): - case CASE( TULONG, TIND): - a = AMOVL; /* same effect as AMOVLQZX */ - if(f->op == OCONST) { - f->vconst &= (uvlong)0xffffffffU; - a = AMOVQ; + case TUINT: + case TULONG: + if(tt == TFLOAT || tt == TDOUBLE) { + // ugly and probably longer than necessary, + // but vfp has a single instruction for this, + // so hopefully it won't last long. + // + // tmp = f + // tmp1 = tmp & 0x80000000 + // tmp ^= tmp1 + // t = float(int32(tmp)) + // if(tmp1) + // t += 2147483648. + // + regalloc(&nod, f, Z); + regalloc(&nod1, f, Z); + gins(AMOVW, f, &nod); + gins(AMOVW, &nod, &nod1); + gins(AAND, nodconst(0x80000000), &nod1); + gins(AEOR, &nod1, &nod); + if(tt == TFLOAT) + gins(AMOVWF, &nod, t); + else + gins(AMOVWD, &nod, t); + gins(ACMP, nodconst(0), Z); + raddr(&nod1, p); + gins(ABEQ, Z, Z); + regfree(&nod); + regfree(&nod1); + p1 = p; + regalloc(&nod, t, Z); + gins(AMOVF, nodfconst(2147483648.), &nod); + gins(AADDF, &nod, t); + regfree(&nod); + patch(p1, pc); + return; + } + // fall through + + case TINT: + case TLONG: + case TIND: + switch(tt) { + case TDOUBLE: + gins(AMOVWD, f, t); + return; + case TFLOAT: + gins(AMOVWF, f, t); + return; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + case TSHORT: + case TUSHORT: + case TCHAR: + case TUCHAR: + a = AMOVW; + break; } break; - - case CASE( TIND, TVLONG): - case CASE( TVLONG, TVLONG): - case CASE( TUVLONG, TVLONG): - case CASE( TVLONG, TUVLONG): - case CASE( TUVLONG, TUVLONG): - case CASE( TIND, TUVLONG): - case CASE( TVLONG, TIND): - case CASE( TUVLONG, TIND): - case CASE( TIND, TIND): - a = AMOVQ; - break; - - case CASE( TSHORT, TINT): - case CASE( TSHORT, TUINT): - case CASE( TSHORT, TLONG): - case CASE( TSHORT, TULONG): - a = AMOVWLSX; - if(f->op == OCONST) { - f->vconst &= 0xffff; - if(f->vconst & 0x8000) - f->vconst |= 0xffff0000; - a = AMOVL; + case TSHORT: + switch(tt) { + case TDOUBLE: + regalloc(&nod, f, Z); + gins(AMOVH, f, &nod); + gins(AMOVWD, &nod, t); + regfree(&nod); + return; + case TFLOAT: + regalloc(&nod, f, Z); + gins(AMOVH, f, &nod); + gins(AMOVWF, &nod, t); + regfree(&nod); + return; + case TUINT: + case TINT: + case TULONG: + case TLONG: + case TIND: + a = AMOVH; + break; + case TSHORT: + case TUSHORT: + case TCHAR: + case TUCHAR: + a = AMOVW; + break; } break; - - case CASE( TSHORT, TVLONG): - case CASE( TSHORT, TUVLONG): - case CASE( TSHORT, TIND): - a = AMOVWQSX; - if(f->op == OCONST) { - f->vconst &= 0xffff; - if(f->vconst & 0x8000){ - f->vconst |= 0xffff0000; - f->vconst |= (vlong)~0 << 32; - } - a = AMOVL; + case TUSHORT: + switch(tt) { + case TDOUBLE: + regalloc(&nod, f, Z); + gins(AMOVHU, f, &nod); + gins(AMOVWD, &nod, t); + regfree(&nod); + return; + case TFLOAT: + regalloc(&nod, f, Z); + gins(AMOVHU, f, &nod); + gins(AMOVWF, &nod, t); + regfree(&nod); + return; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + a = AMOVHU; + break; + case TSHORT: + case TUSHORT: + case TCHAR: + case TUCHAR: + a = AMOVW; + break; } break; - - case CASE( TUSHORT,TINT): - case CASE( TUSHORT,TUINT): - case CASE( TUSHORT,TLONG): - case CASE( TUSHORT,TULONG): - a = AMOVWLZX; - if(f->op == OCONST) { - f->vconst &= 0xffff; - a = AMOVL; + case TCHAR: + switch(tt) { + case TDOUBLE: + regalloc(&nod, f, Z); + gins(AMOVB, f, &nod); + gins(AMOVWD, &nod, t); + regfree(&nod); + return; + case TFLOAT: + regalloc(&nod, f, Z); + gins(AMOVB, f, &nod); + gins(AMOVWF, &nod, t); + regfree(&nod); + return; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + case TSHORT: + case TUSHORT: + a = AMOVB; + break; + case TCHAR: + case TUCHAR: + a = AMOVW; + break; } break; - - case CASE( TUSHORT,TVLONG): - case CASE( TUSHORT,TUVLONG): - case CASE( TUSHORT,TIND): - a = AMOVWQZX; - if(f->op == OCONST) { - f->vconst &= 0xffff; - a = AMOVL; /* MOVL also zero-extends to 64 bits */ + case TUCHAR: + switch(tt) { + case TDOUBLE: + regalloc(&nod, f, Z); + gins(AMOVBU, f, &nod); + gins(AMOVWD, &nod, t); + regfree(&nod); + return; + case TFLOAT: + regalloc(&nod, f, Z); + gins(AMOVBU, f, &nod); + gins(AMOVWF, &nod, t); + regfree(&nod); + return; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + case TSHORT: + case TUSHORT: + a = AMOVBU; + break; + case TCHAR: + case TUCHAR: + a = AMOVW; + break; } break; - - case CASE( TCHAR, TSHORT): - case CASE( TCHAR, TUSHORT): - case CASE( TCHAR, TINT): - case CASE( TCHAR, TUINT): - case CASE( TCHAR, TLONG): - case CASE( TCHAR, TULONG): - a = AMOVBLSX; - if(f->op == OCONST) { - f->vconst &= 0xff; - if(f->vconst & 0x80) - f->vconst |= 0xffffff00; - a = AMOVL; - } - break; - - case CASE( TCHAR, TVLONG): - case CASE( TCHAR, TUVLONG): - case CASE( TCHAR, TIND): - a = AMOVBQSX; - if(f->op == OCONST) { - f->vconst &= 0xff; - if(f->vconst & 0x80){ - f->vconst |= 0xffffff00; - f->vconst |= (vlong)~0 << 32; - } - a = AMOVQ; - } - break; - - case CASE( TUCHAR, TSHORT): - case CASE( TUCHAR, TUSHORT): - case CASE( TUCHAR, TINT): - case CASE( TUCHAR, TUINT): - case CASE( TUCHAR, TLONG): - case CASE( TUCHAR, TULONG): - a = AMOVBLZX; - if(f->op == OCONST) { - f->vconst &= 0xff; - a = AMOVL; - } - break; - - case CASE( TUCHAR, TVLONG): - case CASE( TUCHAR, TUVLONG): - case CASE( TUCHAR, TIND): - a = AMOVBQZX; - if(f->op == OCONST) { - f->vconst &= 0xff; - a = AMOVL; /* zero-extends to 64-bits */ - } - break; - -/* - * float to fix - */ - case CASE( TFLOAT, TCHAR): - case CASE( TFLOAT, TUCHAR): - case CASE( TFLOAT, TSHORT): - case CASE( TFLOAT, TUSHORT): - case CASE( TFLOAT, TINT): - case CASE( TFLOAT, TUINT): - case CASE( TFLOAT, TLONG): - case CASE( TFLOAT, TULONG): - case CASE( TFLOAT, TVLONG): - case CASE( TFLOAT, TUVLONG): - case CASE( TFLOAT, TIND): - - case CASE( TDOUBLE,TCHAR): - case CASE( TDOUBLE,TUCHAR): - case CASE( TDOUBLE,TSHORT): - case CASE( TDOUBLE,TUSHORT): - case CASE( TDOUBLE,TINT): - case CASE( TDOUBLE,TUINT): - case CASE( TDOUBLE,TLONG): - case CASE( TDOUBLE,TULONG): - case CASE( TDOUBLE,TVLONG): - case CASE( TDOUBLE,TUVLONG): - case CASE( TDOUBLE,TIND): - regalloc(&nod, t, Z); - if(ewidth[tt] == SZ_VLONG || typeu[tt] && ewidth[tt] == SZ_INT){ - if(ft == TFLOAT) - a = ACVTTSS2SQ; - else - a = ACVTTSD2SQ; - }else{ - if(ft == TFLOAT) - a = ACVTTSS2SL; - else - a = ACVTTSD2SL; - } - gins(a, f, &nod); - gmove(&nod, t); - regfree(&nod); - return; - -/* - * ulong to float - */ - case CASE( TUVLONG, TDOUBLE): - case CASE( TUVLONG, TFLOAT): - a = ACVTSQ2SS; - if(tt == TDOUBLE) - a = ACVTSQ2SD; - regalloc(&nod, f, f); - gmove(f, &nod); - regalloc(&nod1, t, t); - gins(ACMPQ, &nod, nodconst(0)); - gins(AJLT, Z, Z); - p1 = p; - gins(a, &nod, &nod1); - gins(AJMP, Z, Z); - p2 = p; - patch(p1, pc); - regalloc(&nod2, f, Z); - regalloc(&nod3, f, Z); - gmove(&nod, &nod2); - gins(ASHRQ, nodconst(1), &nod2); - gmove(&nod, &nod3); - gins(AANDL, nodconst(1), &nod3); - gins(AORQ, &nod3, &nod2); - gins(a, &nod2, &nod1); - gins(tt == TDOUBLE? AADDSD: AADDSS, &nod1, &nod1); - regfree(&nod2); - regfree(&nod3); - patch(p2, pc); - regfree(&nod); - regfree(&nod1); - return; - - case CASE( TULONG, TDOUBLE): - case CASE( TUINT, TDOUBLE): - case CASE( TULONG, TFLOAT): - case CASE( TUINT, TFLOAT): - a = ACVTSQ2SS; - if(tt == TDOUBLE) - a = ACVTSQ2SD; - regalloc(&nod, f, f); - gins(AMOVLQZX, f, &nod); - regalloc(&nod1, t, t); - gins(a, &nod, &nod1); - gmove(&nod1, t); - regfree(&nod); - regfree(&nod1); - return; - -/* - * fix to float - */ - case CASE( TCHAR, TFLOAT): - case CASE( TUCHAR, TFLOAT): - case CASE( TSHORT, TFLOAT): - case CASE( TUSHORT,TFLOAT): - case CASE( TINT, TFLOAT): - case CASE( TLONG, TFLOAT): - case CASE( TVLONG, TFLOAT): - case CASE( TIND, TFLOAT): - - case CASE( TCHAR, TDOUBLE): - case CASE( TUCHAR, TDOUBLE): - case CASE( TSHORT, TDOUBLE): - case CASE( TUSHORT,TDOUBLE): - case CASE( TINT, TDOUBLE): - case CASE( TLONG, TDOUBLE): - case CASE( TVLONG, TDOUBLE): - case CASE( TIND, TDOUBLE): - regalloc(&nod, t, t); - if(ewidth[ft] == SZ_VLONG){ - if(tt == TFLOAT) - a = ACVTSQ2SS; - else - a = ACVTSQ2SD; - }else{ - if(tt == TFLOAT) - a = ACVTSL2SS; - else - a = ACVTSL2SD; - } - gins(a, f, &nod); - gmove(&nod, t); - regfree(&nod); - return; - -/* - * float to float - */ - case CASE( TFLOAT, TFLOAT): - a = AMOVSS; - break; - case CASE( TDOUBLE,TFLOAT): - a = ACVTSD2SS; - break; - case CASE( TFLOAT, TDOUBLE): - a = ACVTSS2SD; - break; - case CASE( TDOUBLE,TDOUBLE): - a = AMOVSD; - break; } - if(a == AMOVQ || a == AMOVSD || a == AMOVSS || a == AMOVL && ewidth[ft] == ewidth[tt]) /* TO DO: check AMOVL */ + if(a == AGOK) + diag(Z, "bad opcode in gmove %T -> %T", f->type, t->type); + if(a == AMOVW || a == AMOVF || a == AMOVD) if(samaddr(f, t)) return; gins(a, f, t); } void -doindex(Node *n) +gmover(Node *f, Node *t) { - Node nod, nod1; - long v; + int ft, tt, a; -if(debug['Y']) -prtree(n, "index"); - -if(n->left->complex >= FNX) -print("botch in doindex\n"); - - regalloc(&nod, &qregnode, Z); - v = constnode.vconst; - cgen(n->right, &nod); - idx.ptr = D_NONE; - if(n->left->op == OCONST) - idx.ptr = D_CONST; - else if(n->left->op == OREGISTER) - idx.ptr = n->left->reg; - else if(n->left->op != OADDR) { - reg[D_BP]++; // cant be used as a base - regalloc(&nod1, &qregnode, Z); - cgen(n->left, &nod1); - idx.ptr = nod1.reg; - regfree(&nod1); - reg[D_BP]--; + ft = f->type->etype; + tt = t->type->etype; + a = AGOK; + if(typechlp[ft] && typechlp[tt] && ewidth[ft] >= ewidth[tt]){ + switch(tt){ + case TSHORT: + a = AMOVH; + break; + case TUSHORT: + a = AMOVHU; + break; + case TCHAR: + a = AMOVB; + break; + case TUCHAR: + a = AMOVBU; + break; + } } - idx.reg = nod.reg; - regfree(&nod); - constnode.vconst = v; + if(a == AGOK) + gmove(f, t); + else + gins(a, f, t); } void gins(int a, Node *f, Node *t) { - if(f != Z && f->op == OINDEX) - doindex(f); - if(t != Z && t->op == OINDEX) - doindex(t); nextpc(); p->as = a; if(f != Z) @@ -1159,191 +927,121 @@ } void -gopcode(int o, Type *ty, Node *f, Node *t) +gopcode(int o, Node *f1, Node *f2, Node *t) { int a, et; + Adr ta; et = TLONG; - if(ty != T) - et = ty->etype; - if(debug['M']) { - if(f != Z && f->type != T) - print("gop: %O %O[%s],", o, f->op, tnames[et]); - else - print("gop: %O Z,", o); - if(t != Z && t->type != T) - print("%O[%s]\n", t->op, tnames[t->type->etype]); - else - print("Z\n"); - } + if(f1 != Z && f1->type != T) + et = f1->type->etype; a = AGOK; switch(o) { - case OCOM: - a = ANOTL; - if(et == TCHAR || et == TUCHAR) - a = ANOTB; - if(et == TSHORT || et == TUSHORT) - a = ANOTW; - if(et == TVLONG || et == TUVLONG || et == TIND) - a = ANOTQ; - break; - - case ONEG: - a = ANEGL; - if(et == TCHAR || et == TUCHAR) - a = ANEGB; - if(et == TSHORT || et == TUSHORT) - a = ANEGW; - if(et == TVLONG || et == TUVLONG || et == TIND) - a = ANEGQ; - break; - - case OADDR: - a = ALEAQ; - break; + case OAS: + gmove(f1, t); + return; case OASADD: case OADD: - a = AADDL; - if(et == TCHAR || et == TUCHAR) - a = AADDB; - if(et == TSHORT || et == TUSHORT) - a = AADDW; - if(et == TVLONG || et == TUVLONG || et == TIND) - a = AADDQ; + a = AADD; if(et == TFLOAT) - a = AADDSS; - if(et == TDOUBLE) - a = AADDSD; + a = AADDF; + else + if(et == TDOUBLE || et == TVLONG) + a = AADDD; break; case OASSUB: case OSUB: - a = ASUBL; - if(et == TCHAR || et == TUCHAR) - a = ASUBB; - if(et == TSHORT || et == TUSHORT) - a = ASUBW; - if(et == TVLONG || et == TUVLONG || et == TIND) - a = ASUBQ; + if(f2 && f2->op == OCONST) { + Node *t = f1; + f1 = f2; + f2 = t; + a = ARSB; + } else + a = ASUB; if(et == TFLOAT) - a = ASUBSS; - if(et == TDOUBLE) - a = ASUBSD; + a = ASUBF; + else + if(et == TDOUBLE || et == TVLONG) + a = ASUBD; break; case OASOR: case OOR: - a = AORL; - if(et == TCHAR || et == TUCHAR) - a = AORB; - if(et == TSHORT || et == TUSHORT) - a = AORW; - if(et == TVLONG || et == TUVLONG || et == TIND) - a = AORQ; + a = AORR; break; case OASAND: case OAND: - a = AANDL; - if(et == TCHAR || et == TUCHAR) - a = AANDB; - if(et == TSHORT || et == TUSHORT) - a = AANDW; - if(et == TVLONG || et == TUVLONG || et == TIND) - a = AANDQ; + a = AAND; break; case OASXOR: case OXOR: - a = AXORL; - if(et == TCHAR || et == TUCHAR) - a = AXORB; - if(et == TSHORT || et == TUSHORT) - a = AXORW; - if(et == TVLONG || et == TUVLONG || et == TIND) - a = AXORQ; + a = AEOR; break; case OASLSHR: case OLSHR: - a = ASHRL; - if(et == TCHAR || et == TUCHAR) - a = ASHRB; - if(et == TSHORT || et == TUSHORT) - a = ASHRW; - if(et == TVLONG || et == TUVLONG || et == TIND) - a = ASHRQ; + a = ASRL; break; case OASASHR: case OASHR: - a = ASARL; - if(et == TCHAR || et == TUCHAR) - a = ASARB; - if(et == TSHORT || et == TUSHORT) - a = ASARW; - if(et == TVLONG || et == TUVLONG || et == TIND) - a = ASARQ; + a = ASRA; break; case OASASHL: case OASHL: - a = ASALL; - if(et == TCHAR || et == TUCHAR) - a = ASALB; - if(et == TSHORT || et == TUSHORT) - a = ASALW; - if(et == TVLONG || et == TUVLONG || et == TIND) - a = ASALQ; + a = ASLL; break; case OFUNC: - a = ACALL; + a = ABL; break; case OASMUL: case OMUL: - if(f->op == OREGISTER && t != Z && isreg(t, D_AX) && reg[D_DX] == 0) - t = Z; - a = AIMULL; - if(et == TVLONG || et == TUVLONG || et == TIND) - a = AIMULQ; + a = AMUL; if(et == TFLOAT) - a = AMULSS; - if(et == TDOUBLE) - a = AMULSD; + a = AMULF; + else + if(et == TDOUBLE || et == TVLONG) + a = AMULD; + break; + + case OASDIV: + case ODIV: + a = ADIV; + if(et == TFLOAT) + a = ADIVF; + else + if(et == TDOUBLE || et == TVLONG) + a = ADIVD; break; case OASMOD: case OMOD: - case OASDIV: - case ODIV: - a = AIDIVL; - if(et == TVLONG || et == TUVLONG || et == TIND) - a = AIDIVQ; - if(et == TFLOAT) - a = ADIVSS; - if(et == TDOUBLE) - a = ADIVSD; + a = AMOD; break; case OASLMUL: case OLMUL: - a = AMULL; - if(et == TVLONG || et == TUVLONG || et == TIND) - a = AMULQ; + a = AMULU; break; case OASLMOD: case OLMOD: + a = AMODU; + break; + case OASLDIV: case OLDIV: - a = ADIVL; - if(et == TVLONG || et == TUVLONG || et == TIND) - a = ADIVQ; + a = ADIVU; break; + case OCASE: case OEQ: case ONE: case OLT: @@ -1354,42 +1052,93 @@ case OLS: case OHS: case OHI: - a = ACMPL; - if(et == TCHAR || et == TUCHAR) - a = ACMPB; - if(et == TSHORT || et == TUSHORT) - a = ACMPW; - if(et == TVLONG || et == TUVLONG || et == TIND) - a = ACMPQ; + a = ACMP; if(et == TFLOAT) - a = AUCOMISS; - if(et == TDOUBLE) - a = AUCOMISD; - gins(a, f, t); + a = ACMPF; + else + if(et == TDOUBLE || et == TVLONG) + a = ACMPD; + nextpc(); + p->as = a; + naddr(f1, &p->from); + if(a == ACMP && f1->op == OCONST && p->from.offset < 0) { + p->as = ACMN; + p->from.offset = -p->from.offset; + } + raddr(f2, p); switch(o) { - case OEQ: a = AJEQ; break; - case ONE: a = AJNE; break; - case OLT: a = AJLT; break; - case OLE: a = AJLE; break; - case OGE: a = AJGE; break; - case OGT: a = AJGT; break; - case OLO: a = AJCS; break; - case OLS: a = AJLS; break; - case OHS: a = AJCC; break; - case OHI: a = AJHI; break; + case OEQ: + a = ABEQ; + break; + case ONE: + a = ABNE; + break; + case OLT: + a = ABLT; + break; + case OLE: + a = ABLE; + break; + case OGE: + a = ABGE; + break; + case OGT: + a = ABGT; + break; + case OLO: + a = ABLO; + break; + case OLS: + a = ABLS; + break; + case OHS: + a = ABHS; + break; + case OHI: + a = ABHI; + break; + case OCASE: + nextpc(); + p->as = ACASE; + p->scond = 0x9; + naddr(f2, &p->from); + a = ABHI; + break; } - gins(a, Z, Z); - return; + f1 = Z; + f2 = Z; + break; } if(a == AGOK) diag(Z, "bad in gopcode %O", o); - gins(a, f, t); + nextpc(); + p->as = a; + if(f1 != Z) + naddr(f1, &p->from); + if(f2 != Z) { + naddr(f2, &ta); + p->reg = ta.reg; + } + if(t != Z) + naddr(t, &p->to); + if(debug['g']) + print("%P\n", p); } int samaddr(Node *f, Node *t) { - return f->op == OREGISTER && t->op == OREGISTER && f->reg == t->reg; + + if(f->op != t->op) + return 0; + switch(f->op) { + + case OREGISTER: + if(f->reg != t->reg) + break; + return 1; + } + return 0; } void @@ -1403,7 +1152,7 @@ a = ARET; break; case OGOTO: - a = AJMP; + a = AB; break; } nextpc(); @@ -1415,7 +1164,7 @@ } void -patch(Prog *op, long pc) +patch(Prog *op, int32 pc) { op->to.offset = pc; @@ -1428,11 +1177,15 @@ nextpc(); p->as = a; - p->from.type = D_EXTERN; + p->from.type = D_OREG; p->from.sym = s; - p->from.scale = (profileflg ? 0 : NOPROF); + p->from.name = D_EXTERN; + if(a == ATEXT) { + p->reg = textflag; + textflag = 0; + } if(s->class == CSTATIC) - p->from.type = D_STATIC; + p->from.name = D_STATIC; naddr(n, &p->to); if(a == ADATA || a == AGLOBL) pc--; @@ -1441,74 +1194,105 @@ int sconst(Node *n) { - long v; + vlong vv; - if(n->op == OCONST && !typefd[n->type->etype]) { - v = n->vconst; - if(v >= -32766L && v < 32766L) + if(n->op == OCONST) { + if(!typefd[n->type->etype]) { + vv = n->vconst; + if(vv >= (vlong)(-32766) && vv < (vlong)32766) + return 1; + /* + * should be specialised for constant values which will + * fit in different instructionsl; for now, let 5l + * sort it out + */ return 1; + } } return 0; } -long +int +sval(int32 v) +{ + int i; + + for(i=0; i<16; i++) { + if((v & ~0xff) == 0) + return 1; + if((~v & ~0xff) == 0) + return 1; + v = (v<<2) | ((uint32)v>>30); + } + return 0; +} + +int32 exreg(Type *t) { - long o; + int32 o; - if(typechlpv[t->etype]) { + if(typechlp[t->etype]) { if(exregoffset <= REGEXT-4) return 0; o = exregoffset; exregoffset--; return o; } + if(typefd[t->etype]) { + if(exfregoffset <= NFREG-1) + return 0; + o = exfregoffset + NREG; + exfregoffset--; + return o; + } return 0; } schar ewidth[NTYPE] = { - -1, /*[TXXX]*/ - SZ_CHAR, /*[TCHAR]*/ - SZ_CHAR, /*[TUCHAR]*/ - SZ_SHORT, /*[TSHORT]*/ - SZ_SHORT, /*[TUSHORT]*/ - SZ_INT, /*[TINT]*/ - SZ_INT, /*[TUINT]*/ - SZ_LONG, /*[TLONG]*/ - SZ_LONG, /*[TULONG]*/ - SZ_VLONG, /*[TVLONG]*/ - SZ_VLONG, /*[TUVLONG]*/ - SZ_FLOAT, /*[TFLOAT]*/ - SZ_DOUBLE, /*[TDOUBLE]*/ - SZ_IND, /*[TIND]*/ - 0, /*[TFUNC]*/ - -1, /*[TARRAY]*/ - 0, /*[TVOID]*/ - -1, /*[TSTRUCT]*/ - -1, /*[TUNION]*/ - SZ_INT, /*[TENUM]*/ + -1, /* [TXXX] */ + SZ_CHAR, /* [TCHAR] */ + SZ_CHAR, /* [TUCHAR] */ + SZ_SHORT, /* [TSHORT] */ + SZ_SHORT, /* [TUSHORT] */ + SZ_INT, /* [TINT] */ + SZ_INT, /* [TUINT] */ + SZ_LONG, /* [TLONG] */ + SZ_LONG, /* [TULONG] */ + SZ_VLONG, /* [TVLONG] */ + SZ_VLONG, /* [TUVLONG] */ + SZ_FLOAT, /* [TFLOAT] */ + SZ_DOUBLE, /* [TDOUBLE] */ + SZ_IND, /* [TIND] */ + 0, /* [TFUNC] */ + -1, /* [TARRAY] */ + 0, /* [TVOID] */ + -1, /* [TSTRUCT] */ + -1, /* [TUNION] */ + SZ_INT, /* [TENUM] */ }; -long ncast[NTYPE] = + +int32 ncast[NTYPE] = { - 0, /*[TXXX]*/ - BCHAR|BUCHAR, /*[TCHAR]*/ - BCHAR|BUCHAR, /*[TUCHAR]*/ - BSHORT|BUSHORT, /*[TSHORT]*/ - BSHORT|BUSHORT, /*[TUSHORT]*/ - BINT|BUINT|BLONG|BULONG, /*[TINT]*/ - BINT|BUINT|BLONG|BULONG, /*[TUINT]*/ - BINT|BUINT|BLONG|BULONG, /*[TLONG]*/ - BINT|BUINT|BLONG|BULONG, /*[TULONG]*/ - BVLONG|BUVLONG|BIND, /*[TVLONG]*/ - BVLONG|BUVLONG|BIND, /*[TUVLONG]*/ - BFLOAT, /*[TFLOAT]*/ - BDOUBLE, /*[TDOUBLE]*/ - BVLONG|BUVLONG|BIND, /*[TIND]*/ - 0, /*[TFUNC]*/ - 0, /*[TARRAY]*/ - 0, /*[TVOID]*/ - BSTRUCT, /*[TSTRUCT]*/ - BUNION, /*[TUNION]*/ - 0, /*[TENUM]*/ + 0, /* [TXXX] */ + BCHAR|BUCHAR, /* [TCHAR] */ + BCHAR|BUCHAR, /* [TUCHAR] */ + BSHORT|BUSHORT, /* [TSHORT] */ + BSHORT|BUSHORT, /* [TUSHORT] */ + BINT|BUINT|BLONG|BULONG|BIND, /* [TINT] */ + BINT|BUINT|BLONG|BULONG|BIND, /* [TUINT] */ + BINT|BUINT|BLONG|BULONG|BIND, /* [TLONG] */ + BINT|BUINT|BLONG|BULONG|BIND, /* [TULONG] */ + BVLONG|BUVLONG, /* [TVLONG] */ + BVLONG|BUVLONG, /* [TUVLONG] */ + BFLOAT, /* [TFLOAT] */ + BDOUBLE, /* [TDOUBLE] */ + BLONG|BULONG|BIND, /* [TIND] */ + 0, /* [TFUNC] */ + 0, /* [TARRAY] */ + 0, /* [TVOID] */ + BSTRUCT, /* [TSTRUCT] */ + BUNION, /* [TUNION] */ + 0, /* [TENUM] */ }; diff -r d8d00747375b sys/src/cmd/6c/vlrt.c --- a/sys/src/cmd/6c/vlrt.c Thu Sep 29 03:00:00 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,746 +0,0 @@ -typedef unsigned long ulong; -typedef unsigned int uint; -typedef unsigned short ushort; -typedef unsigned char uchar; -typedef signed char schar; - -#define SIGN(n) (1UL<<(n-1)) - -typedef struct Vlong Vlong; -struct Vlong -{ - union - { - struct - { - uint lo; - uint hi; - }; - struct - { - ushort lols; - ushort loms; - ushort hils; - ushort hims; - }; - }; -}; - -void abort(void); - -void _subv(Vlong*, Vlong, Vlong); - -void -_d2v(Vlong *y, double d) -{ - union { double d; struct Vlong; } x; - uint xhi, xlo, ylo, yhi; - int sh; - - x.d = d; - - xhi = (x.hi & 0xfffff) | 0x100000; - xlo = x.lo; - sh = 1075 - ((x.hi >> 20) & 0x7ff); - - ylo = 0; - yhi = 0; - if(sh >= 0) { - /* v = (hi||lo) >> sh */ - if(sh < 32) { - if(sh == 0) { - ylo = xlo; - yhi = xhi; - } else { - ylo = (xlo >> sh) | (xhi << (32-sh)); - yhi = xhi >> sh; - } - } else { - if(sh == 32) { - ylo = xhi; - } else - if(sh < 64) { - ylo = xhi >> (sh-32); - } - } - } else { - /* v = (hi||lo) << -sh */ - sh = -sh; - if(sh <= 10) { - ylo = xlo << sh; - yhi = (xhi << sh) | (xlo >> (32-sh)); - } else { - /* overflow */ - yhi = d; /* causes something awful */ - } - } - if(x.hi & SIGN(32)) { - if(ylo != 0) { - ylo = -ylo; - yhi = ~yhi; - } else - yhi = -yhi; - } - - y->hi = yhi; - y->lo = ylo; -} - -void -_f2v(Vlong *y, float f) -{ - - _d2v(y, f); -} - -double -_v2d(Vlong x) -{ - if(x.hi & SIGN(32)) { - if(x.lo) { - x.lo = -x.lo; - x.hi = ~x.hi; - } else - x.hi = -x.hi; - return -((long)x.hi*4294967296. + x.lo); - } - return (long)x.hi*4294967296. + x.lo; -} - -float -_v2f(Vlong x) -{ - return _v2d(x); -} - -uint _div64by32(Vlong, uint, uint*); -void _mul64by32(Vlong*, Vlong, uint); - -static void -slowdodiv(Vlong num, Vlong den, Vlong *q, Vlong *r) -{ - uint numlo, numhi, denhi, denlo, quohi, quolo, t; - int i; - - numhi = num.hi; - numlo = num.lo; - denhi = den.hi; - denlo = den.lo; - - /* - * get a divide by zero - */ - if(denlo==0 && denhi==0) { - numlo = numlo / denlo; - } - - /* - * set up the divisor and find the number of iterations needed - */ - if(numhi >= SIGN(32)) { - quohi = SIGN(32); - quolo = 0; - } else { - quohi = numhi; - quolo = numlo; - } - i = 0; - while(denhi < quohi || (denhi == quohi && denlo < quolo)) { - denhi = (denhi<<1) | (denlo>>31); - denlo <<= 1; - i++; - } - - quohi = 0; - quolo = 0; - for(; i >= 0; i--) { - quohi = (quohi<<1) | (quolo>>31); - quolo <<= 1; - if(numhi > denhi || (numhi == denhi && numlo >= denlo)) { - t = numlo; - numlo -= denlo; - if(numlo > t) - numhi--; - numhi -= denhi; - quolo |= 1; - } - denlo = (denlo>>1) | (denhi<<31); - denhi >>= 1; - } - - if(q) { - q->lo = quolo; - q->hi = quohi; - } - if(r) { - r->lo = numlo; - r->hi = numhi; - } -} - -static void -dodiv(Vlong num, Vlong den, Vlong *qp, Vlong *rp) -{ - uint n; - Vlong x, q, r; - - if(den.hi > num.hi || (den.hi == num.hi && den.lo > num.lo)){ - if(qp) { - qp->hi = 0; - qp->lo = 0; - } - if(rp) { - rp->hi = num.hi; - rp->lo = num.lo; - } - return; - } - - if(den.hi != 0){ - q.hi = 0; - n = num.hi/den.hi; - _mul64by32(&x, den, n); - if(x.hi > num.hi || (x.hi == num.hi && x.lo > num.lo)) - slowdodiv(num, den, &q, &r); - else { - q.lo = n; - _subv(&r, num, x); - } - } else { - if(num.hi >= den.lo){ - q.hi = n = num.hi/den.lo; - num.hi -= den.lo*n; - } else { - q.hi = 0; - } - q.lo = _div64by32(num, den.lo, &r.lo); - r.hi = 0; - } - if(qp) { - qp->lo = q.lo; - qp->hi = q.hi; - } - if(rp) { - rp->lo = r.lo; - rp->hi = r.hi; - } -} - -void -_divvu(Vlong *q, Vlong n, Vlong d) -{ - - if(n.hi == 0 && d.hi == 0) { - q->hi = 0; - q->lo = n.lo / d.lo; - return; - } - dodiv(n, d, q, 0); -} - -void -_modvu(Vlong *r, Vlong n, Vlong d) -{ - - if(n.hi == 0 && d.hi == 0) { - r->hi = 0; - r->lo = n.lo % d.lo; - return; - } - dodiv(n, d, 0, r); -} - -static void -vneg(Vlong *v) -{ - - if(v->lo == 0) { - v->hi = -v->hi; - return; - } - v->lo = -v->lo; - v->hi = ~v->hi; -} - -void -_divv(Vlong *q, Vlong n, Vlong d) -{ - long nneg, dneg; - - if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) { - q->lo = (long)n.lo / (long)d.lo; - q->hi = ((long)q->lo) >> 31; - return; - } - nneg = n.hi >> 31; - if(nneg) - vneg(&n); - dneg = d.hi >> 31; - if(dneg) - vneg(&d); - dodiv(n, d, q, 0); - if(nneg != dneg) - vneg(q); -} - -void -_modv(Vlong *r, Vlong n, Vlong d) -{ - long nneg, dneg; - - if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) { - r->lo = (long)n.lo % (long)d.lo; - r->hi = ((long)r->lo) >> 31; - return; - } - nneg = n.hi >> 31; - if(nneg) - vneg(&n); - dneg = d.hi >> 31; - if(dneg) - vneg(&d); - dodiv(n, d, 0, r); - if(nneg) - vneg(r); -} - -void -_rshav(Vlong *r, Vlong a, int b) -{ - long t; - - t = a.hi; - if(b >= 32) { - r->hi = t>>31; - if(b >= 64) { - /* this is illegal re C standard */ - r->lo = t>>31; - return; - } - r->lo = t >> (b-32); - return; - } - if(b <= 0) { - r->hi = t; - r->lo = a.lo; - return; - } - r->hi = t >> b; - r->lo = (t << (32-b)) | (a.lo >> b); -} - -void -_rshlv(Vlong *r, Vlong a, int b) -{ - uint t; - - t = a.hi; - if(b >= 32) { - r->hi = 0; - if(b >= 64) { - /* this is illegal re C standard */ - r->lo = 0; - return; - } - r->lo = t >> (b-32); - return; - } - if(b <= 0) { - r->hi = t; - r->lo = a.lo; - return; - } - r->hi = t >> b; - r->lo = (t << (32-b)) | (a.lo >> b); -} - -void -_lshv(Vlong *r, Vlong a, int b) -{ - uint t; - - t = a.lo; - if(b >= 32) { - r->lo = 0; - if(b >= 64) { - /* this is illegal re C standard */ - r->hi = 0; - return; - } - r->hi = t << (b-32); - return; - } - if(b <= 0) { - r->lo = t; - r->hi = a.hi; - return; - } - r->lo = t << b; - r->hi = (t >> (32-b)) | (a.hi << b); -} - -void -_andv(Vlong *r, Vlong a, Vlong b) -{ - r->hi = a.hi & b.hi; - r->lo = a.lo & b.lo; -} - -void -_orv(Vlong *r, Vlong a, Vlong b) -{ - r->hi = a.hi | b.hi; - r->lo = a.lo | b.lo; -} - -void -_xorv(Vlong *r, Vlong a, Vlong b) -{ - r->hi = a.hi ^ b.hi; - r->lo = a.lo ^ b.lo; -} - -void -_vpp(Vlong *l, Vlong *r) -{ - - l->hi = r->hi; - l->lo = r->lo; - r->lo++; - if(r->lo == 0) - r->hi++; -} - -void -_vmm(Vlong *l, Vlong *r) -{ - - l->hi = r->hi; - l->lo = r->lo; - if(r->lo == 0) - r->hi--; - r->lo--; -} - -void -_ppv(Vlong *l, Vlong *r) -{ - - r->lo++; - if(r->lo == 0) - r->hi++; - l->hi = r->hi; - l->lo = r->lo; -} - -void -_mmv(Vlong *l, Vlong *r) -{ - - if(r->lo == 0) - r->hi--; - r->lo--; - l->hi = r->hi; - l->lo = r->lo; -} - -void -_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv) -{ - Vlong t, u; - - u.lo = 0; - u.hi = 0; - switch(type) { - default: - abort(); - break; - - case 1: /* schar */ - t.lo = *(schar*)lv; - t.hi = t.lo >> 31; - fn(&u, t, rv); - *(schar*)lv = u.lo; - break; - - case 2: /* uchar */ - t.lo = *(uchar*)lv; - t.hi = 0; - fn(&u, t, rv); - *(uchar*)lv = u.lo; - break; - - case 3: /* short */ - t.lo = *(short*)lv; - t.hi = t.lo >> 31; - fn(&u, t, rv); - *(short*)lv = u.lo; - break; - - case 4: /* ushort */ - t.lo = *(ushort*)lv; - t.hi = 0; - fn(&u, t, rv); - *(ushort*)lv = u.lo; - break; - - case 9: /* int */ - t.lo = *(int*)lv; - t.hi = t.lo >> 31; - fn(&u, t, rv); - *(int*)lv = u.lo; - break; - - case 10: /* uint */ - t.lo = *(uint*)lv; - t.hi = 0; - fn(&u, t, rv); - *(uint*)lv = u.lo; - break; - - case 5: /* long */ - t.lo = *(long*)lv; - t.hi = t.lo >> 31; - fn(&u, t, rv); - *(long*)lv = u.lo; - break; - - case 6: /* uint */ - t.lo = *(uint*)lv; - t.hi = 0; - fn(&u, t, rv); - *(uint*)lv = u.lo; - break; - - case 7: /* vlong */ - case 8: /* uvlong */ - fn(&u, *(Vlong*)lv, rv); - *(Vlong*)lv = u; - break; - } - *ret = u; -} - -void -_p2v(Vlong *ret, void *p) -{ - long t; - - t = (uint)p; - ret->lo = t; - ret->hi = 0; -} - -void -_sl2v(Vlong *ret, long sl) -{ - long t; - - t = sl; - ret->lo = t; - ret->hi = t >> 31; -} - -void -_ul2v(Vlong *ret, uint ul) -{ - long t; - - t = ul; - ret->lo = t; - ret->hi = 0; -} - -void -_si2v(Vlong *ret, int si) -{ - long t; - - t = si; - ret->lo = t; - ret->hi = t >> 31; -} - -void -_ui2v(Vlong *ret, uint ui) -{ - long t; - - t = ui; - ret->lo = t; - ret->hi = 0; -} - -void -_sh2v(Vlong *ret, long sh) -{ - long t; - - t = (sh << 16) >> 16; - ret->lo = t; - ret->hi = t >> 31; -} - -void -_uh2v(Vlong *ret, uint ul) -{ - long t; - - t = ul & 0xffff; - ret->lo = t; - ret->hi = 0; -} - -void -_sc2v(Vlong *ret, long uc) -{ - long t; - - t = (uc << 24) >> 24; - ret->lo = t; - ret->hi = t >> 31; -} - -void -_uc2v(Vlong *ret, uint ul) -{ - long t; - - t = ul & 0xff; - ret->lo = t; - ret->hi = 0; -} - -long -_v2sc(Vlong rv) -{ - long t; - - t = rv.lo & 0xff; - return (t << 24) >> 24; -} - -long -_v2uc(Vlong rv) -{ - - return rv.lo & 0xff; -} - -long -_v2sh(Vlong rv) -{ - long t; - - t = rv.lo & 0xffff; - return (t << 16) >> 16; -} - -long -_v2uh(Vlong rv) -{ - - return rv.lo & 0xffff; -} - -long -_v2sl(Vlong rv) -{ - - return rv.lo; -} - -long -_v2ul(Vlong rv) -{ - - return rv.lo; -} - -long -_v2si(Vlong rv) -{ - - return rv.lo; -} - -long -_v2ui(Vlong rv) -{ - - return rv.lo; -} - -int -_testv(Vlong rv) -{ - return rv.lo || rv.hi; -} - -int -_eqv(Vlong lv, Vlong rv) -{ - return lv.lo == rv.lo && lv.hi == rv.hi; -} - -int -_nev(Vlong lv, Vlong rv) -{ - return lv.lo != rv.lo || lv.hi != rv.hi; -} - -int -_ltv(Vlong lv, Vlong rv) -{ - return (long)lv.hi < (long)rv.hi || - (lv.hi == rv.hi && lv.lo < rv.lo); -} - -int -_lev(Vlong lv, Vlong rv) -{ - return (long)lv.hi < (long)rv.hi || - (lv.hi == rv.hi && lv.lo <= rv.lo); -} - -int -_gtv(Vlong lv, Vlong rv) -{ - return (long)lv.hi > (long)rv.hi || - (lv.hi == rv.hi && lv.lo > rv.lo); -} - -int -_gev(Vlong lv, Vlong rv) -{ - return (long)lv.hi > (long)rv.hi || - (lv.hi == rv.hi && lv.lo >= rv.lo); -} - -int -_lov(Vlong lv, Vlong rv) -{ - return lv.hi < rv.hi || - (lv.hi == rv.hi && lv.lo < rv.lo); -} - -int -_lsv(Vlong lv, Vlong rv) -{ - return lv.hi < rv.hi || - (lv.hi == rv.hi && lv.lo <= rv.lo); -} - -int -_hiv(Vlong lv, Vlong rv) -{ - return lv.hi > rv.hi || - (lv.hi == rv.hi && lv.lo > rv.lo); -} - -int -_hsv(Vlong lv, Vlong rv) -{ - return lv.hi > rv.hi || - (lv.hi == rv.hi && lv.lo >= rv.lo); -} diff -r d8d00747375b sys/src/cmd/6l/6.out.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/src/cmd/6l/6.out.h Mon Nov 14 17:35:25 2011 +0100 @@ -0,0 +1,867 @@ +// Inferno utils/6c/6.out.h +// http://code.google.com/p/inferno-os/source/browse/utils/6c/6.out.h +// +// 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. + +#define NSYM 50 +#define NSNAME 8 +#define NOPROF (1<<0) +#define DUPOK (1<<1) +#define NOSPLIT (1<<2) +#define RODATA (1<<3) + +/* + * amd64 + */ + +enum as +{ + AXXX, + AAAA, + AAAD, + AAAM, + AAAS, + AADCB, + AADCL, + AADCW, + AADDB, + AADDL, + AADDW, + AADJSP, + AANDB, + AANDL, + AANDW, + AARPL, + ABOUNDL, + ABOUNDW, + ABSFL, + ABSFW, + ABSRL, + ABSRW, + ABTL, + ABTW, + ABTCL, + ABTCW, + ABTRL, + ABTRW, + ABTSL, + ABTSW, + ABYTE, + ACALL, + ACLC, + ACLD, + ACLI, + ACLTS, + ACMC, + ACMPB, + ACMPL, + ACMPW, + ACMPSB, + ACMPSL, + ACMPSW, + ADAA, + ADAS, + ADATA, + ADECB, + ADECL, + ADECQ, + ADECW, + ADIVB, + ADIVL, + ADIVW, + AENTER, + AGLOBL, + AGOK, + AHISTORY, + AHLT, + AIDIVB, + AIDIVL, + AIDIVW, + AIMULB, + AIMULL, + AIMULW, + AINB, + AINL, + AINW, + AINCB, + AINCL, + AINCQ, + AINCW, + AINSB, + AINSL, + AINSW, + AINT, + AINTO, + AIRETL, + AIRETW, + AJCC, + AJCS, + AJCXZL, + AJEQ, + AJGE, + AJGT, + AJHI, + AJLE, + AJLS, + AJLT, + AJMI, + AJMP, + AJNE, + AJOC, + AJOS, + AJPC, + AJPL, + AJPS, + ALAHF, + ALARL, + ALARW, + ALEAL, + ALEAW, + ALEAVEL, + ALEAVEW, + ALOCK, + ALODSB, + ALODSL, + ALODSW, + ALONG, + ALOOP, + ALOOPEQ, + ALOOPNE, + ALSLL, + ALSLW, + AMOVB, + AMOVL, + AMOVW, + AMOVBLSX, + AMOVBLZX, + AMOVBQSX, + AMOVBQZX, + AMOVBWSX, + AMOVBWZX, + AMOVWLSX, + AMOVWLZX, + AMOVWQSX, + AMOVWQZX, + AMOVSB, + AMOVSL, + AMOVSW, + AMULB, + AMULL, + AMULW, + ANAME, + ANEGB, + ANEGL, + ANEGW, + ANOP, + ANOTB, + ANOTL, + ANOTW, + AORB, + AORL, + AORW, + AOUTB, + AOUTL, + AOUTW, + AOUTSB, + AOUTSL, + AOUTSW, + APAUSE, + APOPAL, + APOPAW, + APOPFL, + APOPFW, + APOPL, + APOPW, + APUSHAL, + APUSHAW, + APUSHFL, + APUSHFW, + APUSHL, + APUSHW, + ARCLB, + ARCLL, + ARCLW, + ARCRB, + ARCRL, + ARCRW, + AREP, + AREPN, + ARET, + AROLB, + AROLL, + AROLW, + ARORB, + ARORL, + ARORW, + ASAHF, + ASALB, + ASALL, + ASALW, + ASARB, + ASARL, + ASARW, + ASBBB, + ASBBL, + ASBBW, + ASCASB, + ASCASL, + ASCASW, + ASETCC, + ASETCS, + ASETEQ, + ASETGE, + ASETGT, + ASETHI, + ASETLE, + ASETLS, + ASETLT, + ASETMI, + ASETNE, + ASETOC, + ASETOS, + ASETPC, + ASETPL, + ASETPS, + ACDQ, + ACWD, + ASHLB, + ASHLL, + ASHLW, + ASHRB, + ASHRL, + ASHRW, + ASTC, + ASTD, + ASTI, + ASTOSB, + ASTOSL, + ASTOSW, + ASUBB, + ASUBL, + ASUBW, + ASYSCALL, + ATESTB, + ATESTL, + ATESTW, + ATEXT, + AVERR, + AVERW, + AWAIT, + AWORD, + AXCHGB, + AXCHGL, + AXCHGW, + AXLAT, + AXORB, + AXORL, + AXORW, + + AFMOVB, + AFMOVBP, + AFMOVD, + AFMOVDP, + AFMOVF, + AFMOVFP, + AFMOVL, + AFMOVLP, + AFMOVV, + AFMOVVP, + AFMOVW, + AFMOVWP, + AFMOVX, + AFMOVXP, + + AFCOMB, + AFCOMBP, + AFCOMD, + AFCOMDP, + AFCOMDPP, + AFCOMF, + AFCOMFP, + AFCOML, + AFCOMLP, + AFCOMW, + AFCOMWP, + AFUCOM, + AFUCOMP, + AFUCOMPP, + + AFADDDP, + AFADDW, + AFADDL, + AFADDF, + AFADDD, + + AFMULDP, + AFMULW, + AFMULL, + AFMULF, + AFMULD, + + AFSUBDP, + AFSUBW, + AFSUBL, + AFSUBF, + AFSUBD, + + AFSUBRDP, + AFSUBRW, + AFSUBRL, + AFSUBRF, + AFSUBRD, + + AFDIVDP, + AFDIVW, + AFDIVL, + AFDIVF, + AFDIVD, + + AFDIVRDP, + AFDIVRW, + AFDIVRL, + AFDIVRF, + AFDIVRD, + + AFXCHD, + AFFREE, + + AFLDCW, + AFLDENV, + AFRSTOR, + AFSAVE, + AFSTCW, + AFSTENV, + AFSTSW, + + AF2XM1, + AFABS, + AFCHS, + AFCLEX, + AFCOS, + AFDECSTP, + AFINCSTP, + AFINIT, + AFLD1, + AFLDL2E, + AFLDL2T, + AFLDLG2, + AFLDLN2, + AFLDPI, + AFLDZ, + AFNOP, + AFPATAN, + AFPREM, + AFPREM1, + AFPTAN, + AFRNDINT, + AFSCALE, + AFSIN, + AFSINCOS, + AFSQRT, + AFTST, + AFXAM, + AFXTRACT, + AFYL2X, + AFYL2XP1, + + AEND, + + ADYNT_, + AINIT_, + + ASIGNAME, + + /* extra 32-bit operations */ + ACMPXCHGB, + ACMPXCHGL, + ACMPXCHGW, + ACMPXCHG8B, + ACPUID, + AINVD, + AINVLPG, + ALFENCE, + AMFENCE, + AMOVNTIL, + ARDMSR, + ARDPMC, + ARDTSC, + ARSM, + ASFENCE, + ASYSRET, + AWBINVD, + AWRMSR, + AXADDB, + AXADDL, + AXADDW, + + /* conditional move */ + ACMOVLCC, + ACMOVLCS, + ACMOVLEQ, + ACMOVLGE, + ACMOVLGT, + ACMOVLHI, + ACMOVLLE, + ACMOVLLS, + ACMOVLLT, + ACMOVLMI, + ACMOVLNE, + ACMOVLOC, + ACMOVLOS, + ACMOVLPC, + ACMOVLPL, + ACMOVLPS, + ACMOVQCC, + ACMOVQCS, + ACMOVQEQ, + ACMOVQGE, + ACMOVQGT, + ACMOVQHI, + ACMOVQLE, + ACMOVQLS, + ACMOVQLT, + ACMOVQMI, + ACMOVQNE, + ACMOVQOC, + ACMOVQOS, + ACMOVQPC, + ACMOVQPL, + ACMOVQPS, + ACMOVWCC, + ACMOVWCS, + ACMOVWEQ, + ACMOVWGE, + ACMOVWGT, + ACMOVWHI, + ACMOVWLE, + ACMOVWLS, + ACMOVWLT, + ACMOVWMI, + ACMOVWNE, + ACMOVWOC, + ACMOVWOS, + ACMOVWPC, + ACMOVWPL, + ACMOVWPS, + + /* 64-bit */ + AADCQ, + AADDQ, + AANDQ, + ABSFQ, + ABSRQ, + ABTCQ, + ABTQ, + ABTRQ, + ABTSQ, + ACMPQ, + ACMPSQ, + ACMPXCHGQ, + ACQO, + ADIVQ, + AIDIVQ, + AIMULQ, + AIRETQ, + AJCXZQ, + ALEAQ, + ALEAVEQ, + ALODSQ, + AMOVQ, + AMOVLQSX, + AMOVLQZX, + AMOVNTIQ, + AMOVSQ, + AMULQ, + ANEGQ, + ANOTQ, + AORQ, + APOPFQ, + APOPQ, + APUSHFQ, + APUSHQ, + ARCLQ, + ARCRQ, + AROLQ, + ARORQ, + AQUAD, + ASALQ, + ASARQ, + ASBBQ, + ASCASQ, + ASHLQ, + ASHRQ, + ASTOSQ, + ASUBQ, + ATESTQ, + AXADDQ, + AXCHGQ, + AXORQ, + + /* media */ + AADDPD, + AADDPS, + AADDSD, + AADDSS, + AANDNPD, + AANDNPS, + AANDPD, + AANDPS, + ACMPPD, + ACMPPS, + ACMPSD, + ACMPSS, + ACOMISD, + ACOMISS, + ACVTPD2PL, + ACVTPD2PS, + ACVTPL2PD, + ACVTPL2PS, + ACVTPS2PD, + ACVTPS2PL, + ACVTSD2SL, + ACVTSD2SQ, + ACVTSD2SS, + ACVTSL2SD, + ACVTSL2SS, + ACVTSQ2SD, + ACVTSQ2SS, + ACVTSS2SD, + ACVTSS2SL, + ACVTSS2SQ, + ACVTTPD2PL, + ACVTTPS2PL, + ACVTTSD2SL, + ACVTTSD2SQ, + ACVTTSS2SL, + ACVTTSS2SQ, + ADIVPD, + ADIVPS, + ADIVSD, + ADIVSS, + AEMMS, + AFXRSTOR, + AFXRSTOR64, + AFXSAVE, + AFXSAVE64, + ALDMXCSR, + AMASKMOVOU, + AMASKMOVQ, + AMAXPD, + AMAXPS, + AMAXSD, + AMAXSS, + AMINPD, + AMINPS, + AMINSD, + AMINSS, + AMOVAPD, + AMOVAPS, + AMOVOU, + AMOVHLPS, + AMOVHPD, + AMOVHPS, + AMOVLHPS, + AMOVLPD, + AMOVLPS, + AMOVMSKPD, + AMOVMSKPS, + AMOVNTO, + AMOVNTPD, + AMOVNTPS, + AMOVNTQ, + AMOVO, + AMOVQOZX, + AMOVSD, + AMOVSS, + AMOVUPD, + AMOVUPS, + AMULPD, + AMULPS, + AMULSD, + AMULSS, + AORPD, + AORPS, + APACKSSLW, + APACKSSWB, + APACKUSWB, + APADDB, + APADDL, + APADDQ, + APADDSB, + APADDSW, + APADDUSB, + APADDUSW, + APADDW, + APANDB, + APANDL, + APANDSB, + APANDSW, + APANDUSB, + APANDUSW, + APANDW, + APAND, + APANDN, + APAVGB, + APAVGW, + APCMPEQB, + APCMPEQL, + APCMPEQW, + APCMPGTB, + APCMPGTL, + APCMPGTW, + APEXTRW, + APFACC, + APFADD, + APFCMPEQ, + APFCMPGE, + APFCMPGT, + APFMAX, + APFMIN, + APFMUL, + APFNACC, + APFPNACC, + APFRCP, + APFRCPIT1, + APFRCPI2T, + APFRSQIT1, + APFRSQRT, + APFSUB, + APFSUBR, + APINSRW, + APMADDWL, + APMAXSW, + APMAXUB, + APMINSW, + APMINUB, + APMOVMSKB, + APMULHRW, + APMULHUW, + APMULHW, + APMULLW, + APMULULQ, + APOR, + APSADBW, + APSHUFHW, + APSHUFL, + APSHUFLW, + APSHUFW, + APSLLO, + APSLLL, + APSLLQ, + APSLLW, + APSRAL, + APSRAW, + APSRLO, + APSRLL, + APSRLQ, + APSRLW, + APSUBB, + APSUBL, + APSUBQ, + APSUBSB, + APSUBSW, + APSUBUSB, + APSUBUSW, + APSUBW, + APSWAPL, + APUNPCKHBW, + APUNPCKHLQ, + APUNPCKHQDQ, + APUNPCKHWL, + APUNPCKLBW, + APUNPCKLLQ, + APUNPCKLQDQ, + APUNPCKLWL, + APXOR, + ARCPPS, + ARCPSS, + ARSQRTPS, + ARSQRTSS, + ASHUFPD, + ASHUFPS, + ASQRTPD, + ASQRTPS, + ASQRTSD, + ASQRTSS, + ASTMXCSR, + ASUBPD, + ASUBPS, + ASUBSD, + ASUBSS, + AUCOMISD, + AUCOMISS, + AUNPCKHPD, + AUNPCKHPS, + AUNPCKLPD, + AUNPCKLPS, + AXORPD, + AXORPS, + + APF2IW, + APF2IL, + API2FW, + API2FL, + ARETFW, + ARETFL, + ARETFQ, + ASWAPGS, + + AMODE, + ACRC32B, + ACRC32Q, + + ALAST +}; + +enum +{ + + D_AL = 0, + D_CL, + D_DL, + D_BL, + D_SPB, + D_BPB, + D_SIB, + D_DIB, + D_R8B, + D_R9B, + D_R10B, + D_R11B, + D_R12B, + D_R13B, + D_R14B, + D_R15B, + + D_AX = 16, + D_CX, + D_DX, + D_BX, + D_SP, + D_BP, + D_SI, + D_DI, + D_R8, + D_R9, + D_R10, + D_R11, + D_R12, + D_R13, + D_R14, + D_R15, + + D_AH = 32, + D_CH, + D_DH, + D_BH, + + D_F0 = 36, + + D_M0 = 44, + + D_X0 = 52, + D_X1, + D_X2, + D_X3, + D_X4, + D_X5, + D_X6, + D_X7, + + D_CS = 68, + D_SS, + D_DS, + D_ES, + D_FS, + D_GS, + + D_GDTR, /* global descriptor table register */ + D_IDTR, /* interrupt descriptor table register */ + D_LDTR, /* local descriptor table register */ + D_MSW, /* machine status word */ + D_TASK, /* task register */ + + D_CR = 79, + D_DR = 95, + D_TR = 103, + + D_NONE = 111, + + D_BRANCH = 112, + D_EXTERN = 113, + D_STATIC = 114, + D_AUTO = 115, + D_PARAM = 116, + D_CONST = 117, + D_FCONST = 118, + D_SCONST = 119, + D_ADDR = 120, + + D_FILE, + D_FILE1, + + D_INDIR, /* additive */ + + D_SIZE = D_INDIR + D_INDIR, /* 6l internal */ + D_PCREL, + + T_TYPE = 1<<0, + T_INDEX = 1<<1, + T_OFFSET = 1<<2, + T_FCONST = 1<<3, + T_SYM = 1<<4, + T_SCONST = 1<<5, + T_64 = 1<<6, + T_GOTYPE = 1<<7, + + REGARG = -1, + REGRET = D_AX, + FREGRET = D_X0, + REGSP = D_SP, + REGTMP = D_DI, + REGEXT = D_R15, /* compiler allocates external registers R15 down */ + FREGMIN = D_X0+5, /* first register variable */ + FREGEXT = D_X0+15 /* first external register */ +}; + +/* + * this is the ranlib header + */ +#define SYMDEF "__.SYMDEF" + +/* + * this is the simulated IEEE floating point + */ +typedef struct ieee Ieee; +struct ieee +{ + int32 l; /* contains ls-man 0xffffffff */ + int32 h; /* contains sign 0x80000000 + exp 0x7ff00000 + ms-man 0x000fffff */ +}; diff -r d8d00747375b sys/src/cmd/6l/asm.c --- a/sys/src/cmd/6l/asm.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/6l/asm.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,8 +1,51 @@ +// Inferno utils/6l/asm.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/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. + +// Writing object files. + #include "l.h" +#include "../ld/lib.h" +#include "../ld/elf.h" +#include "../ld/dwarf.h" +#include "../ld/macho.h" +#include "../ld/pe.h" #define Dbufslop 100 -#define PADDR(a) ((a) & ~0xfffffffff0000000ull) +#define PADDR(a) ((uint32)(a) & ~0x80000000) + +char linuxdynld[] = "/lib64/ld-linux-x86-64.so.2"; +char freebsddynld[] = "/libexec/ld-elf.so.1"; +char openbsddynld[] = "/usr/libexec/ld.so"; + +char zeroes[32]; vlong entryvalue(void) @@ -16,435 +59,1053 @@ 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: + if(s->type != STEXT) diag("entry not text: %s", s->name); - } return s->value; } +vlong +datoff(vlong addr) +{ + if(addr >= segdata.vaddr) + return addr - segdata.vaddr + segdata.fileoff; + if(addr >= segtext.vaddr) + return addr - segtext.vaddr + segtext.fileoff; + diag("datoff %#llx", addr); + return 0; +} + +enum { + ElfStrEmpty, + ElfStrInterp, + ElfStrHash, + ElfStrGot, + ElfStrGotPlt, + ElfStrDynamic, + ElfStrDynsym, + ElfStrDynstr, + ElfStrRela, + ElfStrText, + ElfStrData, + ElfStrBss, + ElfStrShstrtab, + ElfStrSymtab, + ElfStrStrtab, + ElfStrRelaPlt, + ElfStrPlt, + ElfStrGnuVersion, + ElfStrGnuVersionR, + NElfStr +}; + +vlong elfstr[NElfStr]; + +static int +needlib(char *name) +{ + char *p; + Sym *s; + + if(*name == '\0') + return 0; + + /* reuse hash code in symbol table */ + p = smprint(".elfload.%s", name); + s = lookup(p, 0); + if(s->type == 0) { + s->type = 100; // avoid SDATA, etc. + return 1; + } + return 0; +} + +int nelfsym = 1; + +static void addpltsym(Sym*); +static void addgotsym(Sym*); + void -wputl(ushort w) +adddynrel(Sym *s, Reloc *r) { - cput(w); - cput(w>>8); + Sym *targ, *rela, *got; + + targ = r->sym; + cursym = s; + + switch(r->type) { + default: + if(r->type >= 256) { + diag("unexpected relocation type %d", r->type); + return; + } + break; + + // Handle relocations found in ELF object files. + case 256 + R_X86_64_PC32: + if(targ->dynimpname != nil && !targ->dynexport) + diag("unexpected R_X86_64_PC32 relocation for dynamic symbol %s", targ->name); + if(targ->type == 0 || targ->type == SXREF) + diag("unknown symbol %s in pcrel", targ->name); + r->type = D_PCREL; + r->add += 4; + return; + + case 256 + R_X86_64_PLT32: + r->type = D_PCREL; + r->add += 4; + if(targ->dynimpname != nil && !targ->dynexport) { + addpltsym(targ); + r->sym = lookup(".plt", 0); + r->add += targ->plt; + } + return; + + case 256 + R_X86_64_GOTPCREL: + if(targ->dynimpname == nil || targ->dynexport) { + // have symbol + if(r->off >= 2 && s->p[r->off-2] == 0x8b) { + // turn MOVQ of GOT entry into LEAQ of symbol itself + s->p[r->off-2] = 0x8d; + r->type = D_PCREL; + r->add += 4; + return; + } + // fall back to using GOT and hope for the best (CMOV*) + // TODO: just needs relocation, no need to put in .dynsym + targ->dynimpname = targ->name; + } + addgotsym(targ); + r->type = D_PCREL; + r->sym = lookup(".got", 0); + r->add += 4; + r->add += targ->got; + return; + + case 256 + R_X86_64_64: + if(targ->dynimpname != nil && !targ->dynexport) + diag("unexpected R_X86_64_64 relocation for dynamic symbol %s", targ->name); + r->type = D_ADDR; + return; + + // Handle relocations found in Mach-O object files. + case 512 + MACHO_X86_64_RELOC_UNSIGNED*2 + 0: + case 512 + MACHO_X86_64_RELOC_SIGNED*2 + 0: + case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 0: + // TODO: What is the difference between all these? + r->type = D_ADDR; + if(targ->dynimpname != nil && !targ->dynexport) + diag("unexpected reloc for dynamic symbol %s", targ->name); + return; + + case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 1: + if(targ->dynimpname != nil && !targ->dynexport) { + addpltsym(targ); + r->sym = lookup(".plt", 0); + r->add = targ->plt; + r->type = D_PCREL; + return; + } + // fall through + case 512 + MACHO_X86_64_RELOC_UNSIGNED*2 + 1: + case 512 + MACHO_X86_64_RELOC_SIGNED*2 + 1: + case 512 + MACHO_X86_64_RELOC_SIGNED_1*2 + 1: + case 512 + MACHO_X86_64_RELOC_SIGNED_2*2 + 1: + case 512 + MACHO_X86_64_RELOC_SIGNED_4*2 + 1: + r->type = D_PCREL; + if(targ->dynimpname != nil && !targ->dynexport) + diag("unexpected pc-relative reloc for dynamic symbol %s", targ->name); + return; + + case 512 + MACHO_X86_64_RELOC_GOT_LOAD*2 + 1: + if(targ->dynimpname == nil || targ->dynexport) { + // have symbol + // turn MOVQ of GOT entry into LEAQ of symbol itself + if(r->off < 2 || s->p[r->off-2] != 0x8b) { + diag("unexpected GOT_LOAD reloc for non-dynamic symbol %s", targ->name); + return; + } + s->p[r->off-2] = 0x8d; + r->type = D_PCREL; + return; + } + // fall through + case 512 + MACHO_X86_64_RELOC_GOT*2 + 1: + if(targ->dynimpname == nil || targ->dynexport) + diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name); + addgotsym(targ); + r->type = D_PCREL; + r->sym = lookup(".got", 0); + r->add += targ->got; + return; + } + + // Handle references to ELF symbols from our own object files. + if(targ->dynimpname == nil || targ->dynexport) + return; + + switch(r->type) { + case D_PCREL: + addpltsym(targ); + r->sym = lookup(".plt", 0); + r->add = targ->plt; + return; + + case D_ADDR: + if(s->type != SDATA) + break; + if(iself) { + adddynsym(targ); + rela = lookup(".rela", 0); + addaddrplus(rela, s, r->off); + if(r->siz == 8) + adduint64(rela, ELF64_R_INFO(targ->dynid, R_X86_64_64)); + else + adduint64(rela, ELF64_R_INFO(targ->dynid, R_X86_64_32)); + adduint64(rela, r->add); + r->type = 256; // ignore during relocsym + return; + } + if(HEADTYPE == Hdarwin && s->size == PtrSize && r->off == 0) { + // Mach-O relocations are a royal pain to lay out. + // They use a compact stateful bytecode representation + // that is too much bother to deal with. + // Instead, interpret the C declaration + // void *_Cvar_stderr = &stderr; + // as making _Cvar_stderr the name of a GOT entry + // for stderr. This is separate from the usual GOT entry, + // just in case the C code assigns to the variable, + // and of course it only works for single pointers, + // but we only need to support cgo and that's all it needs. + adddynsym(targ); + got = lookup(".got", 0); + s->type = got->type | SSUB; + s->outer = got; + s->sub = got->sub; + got->sub = s; + s->value = got->size; + adduint64(got, 0); + adduint32(lookup(".linkedit.got", 0), targ->dynid); + r->type = 256; // ignore during relocsym + return; + } + break; + } + + cursym = s; + diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type); +} + +int +archreloc(Reloc *r, Sym *s, vlong *val) +{ + USED(r); + USED(s); + USED(val); + return -1; +} + +static void +elfsetupplt(void) +{ + Sym *plt, *got; + + plt = lookup(".plt", 0); + got = lookup(".got.plt", 0); + if(plt->size == 0) { + // pushq got+8(IP) + adduint8(plt, 0xff); + adduint8(plt, 0x35); + addpcrelplus(plt, got, 8); + + // jmpq got+16(IP) + adduint8(plt, 0xff); + adduint8(plt, 0x25); + addpcrelplus(plt, got, 16); + + // nopl 0(AX) + adduint32(plt, 0x00401f0f); + + // assume got->size == 0 too + addaddrplus(got, lookup(".dynamic", 0), 0); + adduint64(got, 0); + adduint64(got, 0); + } +} + +static void +addpltsym(Sym *s) +{ + if(s->plt >= 0) + return; + + adddynsym(s); + + if(iself) { + Sym *plt, *got, *rela; + + plt = lookup(".plt", 0); + got = lookup(".got.plt", 0); + rela = lookup(".rela.plt", 0); + if(plt->size == 0) + elfsetupplt(); + + // jmpq *got+size(IP) + adduint8(plt, 0xff); + adduint8(plt, 0x25); + addpcrelplus(plt, got, got->size); + + // add to got: pointer to current pos in plt + addaddrplus(got, plt, plt->size); + + // pushq $x + adduint8(plt, 0x68); + adduint32(plt, (got->size-24-8)/8); + + // jmpq .plt + adduint8(plt, 0xe9); + adduint32(plt, -(plt->size+4)); + + // rela + addaddrplus(rela, got, got->size-8); + adduint64(rela, ELF64_R_INFO(s->dynid, R_X86_64_JMP_SLOT)); + adduint64(rela, 0); + + s->plt = plt->size - 16; + } else if(HEADTYPE == Hdarwin) { + // To do lazy symbol lookup right, we're supposed + // to tell the dynamic loader which library each + // symbol comes from and format the link info + // section just so. I'm too lazy (ha!) to do that + // so for now we'll just use non-lazy pointers, + // which don't need to be told which library to use. + // + // http://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html + // has details about what we're avoiding. + + Sym *plt; + + addgotsym(s); + plt = lookup(".plt", 0); + + adduint32(lookup(".linkedit.plt", 0), s->dynid); + + // jmpq *got+size(IP) + s->plt = plt->size; + + adduint8(plt, 0xff); + adduint8(plt, 0x25); + addpcrelplus(plt, lookup(".got", 0), s->got); + } else { + diag("addpltsym: unsupported binary format"); + } +} + +static void +addgotsym(Sym *s) +{ + Sym *got, *rela; + + if(s->got >= 0) + return; + + adddynsym(s); + got = lookup(".got", 0); + s->got = got->size; + adduint64(got, 0); + + if(iself) { + rela = lookup(".rela", 0); + addaddrplus(rela, got, s->got); + adduint64(rela, ELF64_R_INFO(s->dynid, R_X86_64_GLOB_DAT)); + adduint64(rela, 0); + } else if(HEADTYPE == Hdarwin) { + adduint32(lookup(".linkedit.got", 0), s->dynid); + } else { + diag("addgotsym: unsupported binary format"); + } } void -wput(ushort w) +adddynsym(Sym *s) { - cput(w>>8); - cput(w); + Sym *d, *str; + int t; + char *name; + + if(s->dynid >= 0) + return; + + if(s->dynimpname == nil) + diag("adddynsym: no dynamic name for %s", s->name); + + if(iself) { + s->dynid = nelfsym++; + + d = lookup(".dynsym", 0); + + name = s->dynimpname; + if(name == nil) + name = s->name; + adduint32(d, addstring(lookup(".dynstr", 0), name)); + /* type */ + t = STB_GLOBAL << 4; + if(s->dynexport && s->type == STEXT) + t |= STT_FUNC; + else + t |= STT_OBJECT; + adduint8(d, t); + + /* reserved */ + adduint8(d, 0); + + /* section where symbol is defined */ + if(!s->dynexport && s->dynimpname != nil) + adduint16(d, SHN_UNDEF); + else { + switch(s->type) { + default: + case STEXT: + t = 11; + break; + case SRODATA: + t = 12; + break; + case SDATA: + t = 13; + break; + case SBSS: + t = 14; + break; + } + adduint16(d, t); + } + + /* value */ + if(s->type == SDYNIMPORT) + adduint64(d, 0); + else + addaddr(d, s); + + /* size of object */ + adduint64(d, 0); + + if(!s->dynexport && s->dynimplib && needlib(s->dynimplib)) { + elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, + addstring(lookup(".dynstr", 0), s->dynimplib)); + } + } else if(HEADTYPE == Hdarwin) { + // Mach-o symbol nlist64 + d = lookup(".dynsym", 0); + name = s->dynimpname; + if(name == nil) + name = s->name; + s->dynid = d->size/16; + // darwin still puts _ prefixes on all C symbols + str = lookup(".dynstr", 0); + adduint32(d, str->size); + adduint8(str, '_'); + addstring(str, name); + if(s->type == SDYNIMPORT) { + adduint8(d, 0x01); // type - N_EXT - external symbol + adduint8(d, 0); // section + } else { + adduint8(d, 0x0f); + switch(s->type) { + default: + case STEXT: + adduint8(d, 1); + break; + case SDATA: + adduint8(d, 2); + break; + case SBSS: + adduint8(d, 4); + break; + } + } + adduint16(d, 0); // desc + if(s->type == SDYNIMPORT) + adduint64(d, 0); // value + else + addaddr(d, s); + } else if(HEADTYPE != Hwindows) { + diag("adddynsym: unsupported binary format"); + } } void -lput(long l) +adddynlib(char *lib) { - cput(l>>24); - cput(l>>16); - cput(l>>8); - cput(l); + Sym *s; + + if(!needlib(lib)) + return; + + if(iself) { + s = lookup(".dynstr", 0); + if(s->size == 0) + addstring(s, ""); + elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib)); + } else if(HEADTYPE == Hdarwin) { + machoadddynlib(lib); + } else { + diag("adddynlib: unsupported binary format"); + } } void -llput(vlong v) +doelf(void) { - lput(v>>32); - lput(v); + Sym *s, *shstrtab, *dynstr; + + if(HEADTYPE != Hlinux && HEADTYPE != Hfreebsd && HEADTYPE != Hopenbsd) + return; + + /* predefine strings we need for section headers */ + shstrtab = lookup(".shstrtab", 0); + shstrtab->type = SELFROSECT; + shstrtab->reachable = 1; + + elfstr[ElfStrEmpty] = addstring(shstrtab, ""); + elfstr[ElfStrText] = addstring(shstrtab, ".text"); + elfstr[ElfStrData] = addstring(shstrtab, ".data"); + elfstr[ElfStrBss] = addstring(shstrtab, ".bss"); + addstring(shstrtab, ".elfdata"); + addstring(shstrtab, ".rodata"); + addstring(shstrtab, ".gosymtab"); + addstring(shstrtab, ".gopclntab"); + if(!debug['s']) { + elfstr[ElfStrSymtab] = addstring(shstrtab, ".symtab"); + elfstr[ElfStrStrtab] = addstring(shstrtab, ".strtab"); + dwarfaddshstrings(shstrtab); + } + 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[ElfStrRela] = addstring(shstrtab, ".rela"); + elfstr[ElfStrRelaPlt] = addstring(shstrtab, ".rela.plt"); + elfstr[ElfStrPlt] = addstring(shstrtab, ".plt"); + elfstr[ElfStrGnuVersion] = addstring(shstrtab, ".gnu.version"); + elfstr[ElfStrGnuVersionR] = addstring(shstrtab, ".gnu.version_r"); + + /* dynamic symbol table - first entry all zeros */ + s = lookup(".dynsym", 0); + s->type = SELFROSECT; + s->reachable = 1; + s->size += ELF64SYMSIZE; + + /* dynamic string table */ + s = lookup(".dynstr", 0); + s->type = SELFROSECT; + s->reachable = 1; + if(s->size == 0) + addstring(s, ""); + dynstr = s; + + /* relocation table */ + s = lookup(".rela", 0); + s->reachable = 1; + s->type = SELFROSECT; + + /* global offset table */ + s = lookup(".got", 0); + s->reachable = 1; + s->type = SELFSECT; // writable + + /* hash */ + s = lookup(".hash", 0); + s->reachable = 1; + s->type = SELFROSECT; + + s = lookup(".got.plt", 0); + s->reachable = 1; + s->type = SELFSECT; // writable + + s = lookup(".plt", 0); + s->reachable = 1; + s->type = SELFROSECT; + + elfsetupplt(); + + s = lookup(".rela.plt", 0); + s->reachable = 1; + s->type = SELFROSECT; + + s = lookup(".gnu.version", 0); + s->reachable = 1; + s->type = SELFROSECT; + + s = lookup(".gnu.version_r", 0); + s->reachable = 1; + s->type = SELFROSECT; + + /* define dynamic elf table */ + s = lookup(".dynamic", 0); + s->reachable = 1; + s->type = SELFSECT; // writable + + /* + * .dynamic table + */ + elfwritedynentsym(s, DT_HASH, lookup(".hash", 0)); + elfwritedynentsym(s, DT_SYMTAB, lookup(".dynsym", 0)); + elfwritedynent(s, DT_SYMENT, ELF64SYMSIZE); + elfwritedynentsym(s, DT_STRTAB, lookup(".dynstr", 0)); + elfwritedynentsymsize(s, DT_STRSZ, lookup(".dynstr", 0)); + elfwritedynentsym(s, DT_RELA, lookup(".rela", 0)); + elfwritedynentsymsize(s, DT_RELASZ, lookup(".rela", 0)); + elfwritedynent(s, DT_RELAENT, ELF64RELASIZE); + if(rpath) + elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath)); + + elfwritedynentsym(s, DT_PLTGOT, lookup(".got.plt", 0)); + elfwritedynent(s, DT_PLTREL, DT_RELA); + elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rela.plt", 0)); + elfwritedynentsym(s, DT_JMPREL, lookup(".rela.plt", 0)); + + elfwritedynent(s, DT_DEBUG, 0); + + // Do not write DT_NULL. elfdynhash will finish it. + } } void -lputl(long l) +shsym(ElfShdr *sh, Sym *s) { - cput(l); - cput(l>>8); - cput(l>>16); - cput(l>>24); + vlong addr; + addr = symaddr(s); + if(sh->flags&SHF_ALLOC) + sh->addr = addr; + sh->off = datoff(addr); + sh->size = s->size; } void -strnput(char *s, int n) +phsh(ElfPhdr *ph, ElfShdr *sh) { - for(; *s && n > 0; s++){ - cput(*s); - n--; - } - while(n > 0){ - cput(0); - n--; - } + 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; - long v, magic; - int a; - uchar *op1; - vlong vl; + int32 magic; + int a, dynsym; + vlong vl, startva, symo, dwarfoff, machlink; + ElfEhdr *eh; + ElfPhdr *ph, *pph; + ElfShdr *sh; + Section *sect; + int o; 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; - if(p->pc != pc) { - if(!debug['a']) - print("%P\n", curp); - diag("phase error %llux sb %llux in %s", p->pc, pc, TNAME); - pc = p->pc; - } - curp = p; - asmins(p); - a = (andptr - and); - if(cbc < a) - cflush(); - 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; - } - cflush(); - switch(HEADTYPE) { - default: - diag("unknown header type %ld", HEADTYPE); - case 2: - case 5: - seek(cout, HEADR+textsize, 0); - break; + elftextsh = 0; + + if(debug['v']) + Bprint(&bso, "%5.2f codeblk\n", cputime()); + Bflush(&bso); + + sect = segtext.sect; + cseek(sect->vaddr - segtext.vaddr + segtext.fileoff); + codeblk(sect->vaddr, sect->len); + + /* output read-only data in text segment (rodata, gosymtab and pclntab) */ + for(sect = sect->next; sect != nil; sect = sect->next) { + cseek(sect->vaddr - segtext.vaddr + segtext.fileoff); + datblk(sect->vaddr, sect->len); } if(debug['v']) Bprint(&bso, "%5.2f datblk\n", cputime()); Bflush(&bso); - if(dlm){ - char buf[8]; + cseek(segdata.fileoff); + datblk(segdata.vaddr, segdata.filelen); - write(cout, buf, INITDAT-textsize); - textsize = INITDAT; + machlink = 0; + if(HEADTYPE == Hdarwin) { + if(debug['v']) + Bprint(&bso, "%5.2f dwarf\n", cputime()); + + dwarfoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen, INITRND); + cseek(dwarfoff); + + segdwarf.fileoff = cpos(); + dwarfemitdebugsections(); + segdwarf.filelen = cpos() - segdwarf.fileoff; + + machlink = domacholink(); } - 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); + switch(HEADTYPE) { + default: + diag("unknown header type %d", HEADTYPE); + case Hplan9x32: + case Helf: + break; + case Hdarwin: + debug['8'] = 1; /* 64-bit addresses */ + break; + case Hlinux: + case Hfreebsd: + case Hopenbsd: + debug['8'] = 1; /* 64-bit addresses */ + /* index of elf text section; needed by asmelfsym, double-checked below */ + /* !debug['d'] causes extra sections before the .text section */ + elftextsh = 2; + if(!debug['d']) { + elftextsh += 10; + if(elfverneed) + elftextsh += 2; + } + break; + case Hwindows: + break; } 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 2: - case 5: - seek(cout, HEADR+textsize+datsize, 0); + case Hplan9x32: + case Helf: + debug['s'] = 1; + symo = HEADR+segtext.len+segdata.filelen; + break; + case Hdarwin: + symo = rnd(HEADR+segtext.len, INITRND)+rnd(segdata.filelen, INITRND)+machlink; + break; + case Hlinux: + case Hfreebsd: + case Hopenbsd: + symo = rnd(HEADR+segtext.len, INITRND)+segdata.filelen; + symo = rnd(symo, INITRND); + break; + case Hwindows: + symo = rnd(HEADR+segtext.filelen, PEFILEALIGN)+segdata.filelen; + symo = rnd(symo, PEFILEALIGN); break; } - 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(); + cseek(symo); + switch(HEADTYPE) { + default: + if(iself) { + cseek(symo); + asmelfsym(); + cflush(); + cwrite(elfstrdat, elfstrsize); + + if(debug['v']) + Bprint(&bso, "%5.2f dwarf\n", cputime()); + + dwarfemitdebugsections(); + } + break; + case Hwindows: + if(debug['v']) + Bprint(&bso, "%5.2f dwarf\n", cputime()); + + dwarfemitdebugsections(); + break; + } } - 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); + cseek(0L); switch(HEADTYPE) { default: - case 2: /* plan9 */ + case Hplan9x32: /* plan9 */ magic = 4*26*26+7; magic |= 0x00008000; /* fat header */ - if(dlm) - magic |= 0x80000000; /* dlm */ - lput(magic); /* magic */ - lput(textsize); /* sizes */ - lput(datsize); - lput(bsssize); - lput(symsize); /* nsyms */ + lputb(magic); /* magic */ + lputb(segtext.filelen); /* sizes */ + lputb(segdata.filelen); + lputb(segdata.len - segdata.filelen); + lputb(symsize); /* nsyms */ vl = entryvalue(); - lput(PADDR(vl)); /* va of entry */ - lput(spsize); /* sp offsets */ - lput(lcsize); /* line offsets */ - llput(vl); /* va of entry */ + lputb(PADDR(vl)); /* va of entry */ + lputb(spsize); /* sp offsets */ + lputb(lcsize); /* line offsets */ + vputb(vl); /* va of entry */ break; - case 3: /* plan9 */ + case Hplan9x64: /* plan9 */ magic = 4*26*26+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 */ + lputb(magic); /* magic */ + lputb(segtext.filelen); /* sizes */ + lputb(segdata.filelen); + lputb(segdata.len - segdata.filelen); + lputb(symsize); /* nsyms */ + lputb(entryvalue()); /* va of entry */ + lputb(spsize); /* sp offsets */ + lputb(lcsize); /* line offsets */ break; - case 5: - strnput("\177ELF", 4); /* e_ident */ - cput(1); /* class = 32 bit */ - cput(1); /* data = LSB */ - cput(1); /* version = CURRENT */ - strnput("", 9); - wputl(2); /* type = EXEC */ - if(debug['8']) - wputl(3); /* machine = 386 */ - else - wputl(62); /* machine = AMD64 */ - lputl(1L); /* version = CURRENT */ - lputl(PADDR(entryvalue())); /* entry vaddr */ - lputl(52L); /* offset to first phdr */ - lputl(0L); /* offset to first shdr */ - lputl(0L); /* processor specific flags */ - wputl(52); /* Ehdr size */ - wputl(32); /* Phdr size */ - wputl(3); /* # of Phdrs */ - wputl(0); /* Shdr size */ - wputl(0); /* # of Shdrs */ - wputl(0); /* Shdr string size */ + case Hdarwin: + asmbmacho(); + break; + case Hlinux: + case Hfreebsd: + case Hopenbsd: + /* elf amd-64 */ - lputl(1L); /* text - type = PT_LOAD */ - lputl(HEADR); /* file offset */ - lputl(INITTEXT); /* vaddr */ - lputl(PADDR(INITTEXT)); /* paddr */ - lputl(textsize); /* file size */ - lputl(textsize); /* memory size */ - lputl(0x05L); /* protections = RX */ - lputl(INITRND); /* alignment */ + eh = getElfEhdr(); + startva = INITTEXT - HEADR; - lputl(1L); /* data - type = PT_LOAD */ - lputl(HEADR+textsize); /* file offset */ - lputl(INITDAT); /* vaddr */ - lputl(PADDR(INITDAT)); /* paddr */ - lputl(datsize); /* file size */ - lputl(datsize+bsssize); /* memory size */ - lputl(0x06L); /* protections = RW */ - lputl(INITRND); /* alignment */ + /* This null SHdr must appear before all others */ + newElfShdr(elfstr[ElfStrEmpty]); - lputl(0L); /* data - type = PT_NULL */ - lputl(HEADR+textsize+datsize); /* file offset */ - lputl(0L); - lputl(0L); - lputl(symsize); /* symbol table size */ - lputl(lcsize); /* line number size */ - lputl(0x04L); /* protections = R */ - lputl(0x04L); /* alignment */ + /* program header info */ + 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; + + /* + * PHDR must be in a loaded segment. Adjust the text + * segment boundaries downwards to include it. + */ + o = segtext.vaddr - pph->vaddr; + segtext.vaddr -= o; + segtext.len += o; + o = segtext.fileoff - pph->off; + segtext.fileoff -= o; + segtext.filelen += o; + + if(!debug['d']) { + /* interpreter */ + sh = newElfShdr(elfstr[ElfStrInterp]); + sh->type = SHT_PROGBITS; + sh->flags = SHF_ALLOC; + sh->addralign = 1; + if(interpreter == nil) { + switch(HEADTYPE) { + case Hlinux: + interpreter = linuxdynld; + break; + case Hfreebsd: + interpreter = freebsddynld; + break; + case Hopenbsd: + interpreter = openbsddynld; + break; + } + } + elfinterp(sh, startva, interpreter); + + ph = newElfPhdr(); + ph->type = PT_INTERP; + ph->flags = PF_R; + phsh(ph, sh); + } + + elfphload(&segtext); + elfphload(&segdata); + + /* 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 = 8; + sh->addralign = 8; + shsym(sh, lookup(".got", 0)); + + sh = newElfShdr(elfstr[ElfStrGotPlt]); + sh->type = SHT_PROGBITS; + sh->flags = SHF_ALLOC+SHF_WRITE; + sh->entsize = 8; + sh->addralign = 8; + shsym(sh, lookup(".got.plt", 0)); + + dynsym = eh->shnum; + sh = newElfShdr(elfstr[ElfStrDynsym]); + sh->type = SHT_DYNSYM; + sh->flags = SHF_ALLOC; + sh->entsize = ELF64SYMSIZE; + sh->addralign = 8; + 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)); + + if(elfverneed) { + sh = newElfShdr(elfstr[ElfStrGnuVersion]); + sh->type = SHT_GNU_VERSYM; + sh->flags = SHF_ALLOC; + sh->addralign = 2; + sh->link = dynsym; + sh->entsize = 2; + shsym(sh, lookup(".gnu.version", 0)); + + sh = newElfShdr(elfstr[ElfStrGnuVersionR]); + sh->type = SHT_GNU_VERNEED; + sh->flags = SHF_ALLOC; + sh->addralign = 8; + sh->info = elfverneed; + sh->link = dynsym+1; // dynstr + shsym(sh, lookup(".gnu.version_r", 0)); + } + + sh = newElfShdr(elfstr[ElfStrRelaPlt]); + sh->type = SHT_RELA; + sh->flags = SHF_ALLOC; + sh->entsize = ELF64RELASIZE; + sh->addralign = 8; + sh->link = dynsym; + sh->info = eh->shnum; // .plt + shsym(sh, lookup(".rela.plt", 0)); + + sh = newElfShdr(elfstr[ElfStrPlt]); + sh->type = SHT_PROGBITS; + sh->flags = SHF_ALLOC+SHF_EXECINSTR; + sh->entsize = 16; + sh->addralign = 4; + shsym(sh, lookup(".plt", 0)); + + sh = newElfShdr(elfstr[ElfStrHash]); + sh->type = SHT_HASH; + sh->flags = SHF_ALLOC; + sh->entsize = 4; + sh->addralign = 8; + sh->link = dynsym; + shsym(sh, lookup(".hash", 0)); + + sh = newElfShdr(elfstr[ElfStrRela]); + sh->type = SHT_RELA; + sh->flags = SHF_ALLOC; + sh->entsize = ELF64RELASIZE; + sh->addralign = 8; + sh->link = dynsym; + shsym(sh, lookup(".rela", 0)); + + /* sh and PT_DYNAMIC for .dynamic section */ + sh = newElfShdr(elfstr[ElfStrDynamic]); + sh->type = SHT_DYNAMIC; + sh->flags = SHF_ALLOC+SHF_WRITE; + sh->entsize = 16; + sh->addralign = 8; + 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 = 8; + } + } + + ph = newElfPhdr(); + ph->type = PT_GNU_STACK; + ph->flags = PF_W+PF_R; + ph->align = 8; + + sh = newElfShstrtab(elfstr[ElfStrShstrtab]); + sh->type = SHT_STRTAB; + sh->addralign = 1; + shsym(sh, lookup(".shstrtab", 0)); + + if(elftextsh != eh->shnum) + diag("elftextsh = %d, want %d", elftextsh, eh->shnum); + for(sect=segtext.sect; sect!=nil; sect=sect->next) + elfshbits(sect); + for(sect=segdata.sect; sect!=nil; sect=sect->next) + elfshbits(sect); + + if (!debug['s']) { + sh = newElfShdr(elfstr[ElfStrSymtab]); + sh->type = SHT_SYMTAB; + sh->off = symo; + sh->size = symsize; + sh->addralign = 8; + sh->entsize = 24; + sh->link = eh->shnum; // link to strtab + + sh = newElfShdr(elfstr[ElfStrStrtab]); + sh->type = SHT_STRTAB; + sh->off = symo+symsize; + sh->size = elfstrsize; + sh->addralign = 1; + + dwarfaddelfheaders(); + } + + /* Main header */ + eh->ident[EI_MAG0] = '\177'; + eh->ident[EI_MAG1] = 'E'; + eh->ident[EI_MAG2] = 'L'; + eh->ident[EI_MAG3] = 'F'; + if(HEADTYPE == Hfreebsd) + eh->ident[EI_OSABI] = ELFOSABI_FREEBSD; + else if(HEADTYPE == Hopenbsd) + eh->ident[EI_OSABI] = ELFOSABI_OPENBSD; + eh->ident[EI_CLASS] = ELFCLASS64; + eh->ident[EI_DATA] = ELFDATA2LSB; + eh->ident[EI_VERSION] = EV_CURRENT; + + eh->type = ET_EXEC; + eh->machine = EM_X86_64; + eh->version = EV_CURRENT; + eh->entry = entryvalue(); + + pph->filesz = eh->phnum * eh->phentsize; + pph->memsz = pph->filesz; + + cseek(0); + a = 0; + a += elfwritehdr(); + a += elfwritephdrs(); + a += elfwriteshdrs(); + a += elfwriteinterp(); + if(a > ELFRESERVE) + diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE); + break; + case Hwindows: + asmbpe(); break; } 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); -} - -void -datblk(long s, long n) -{ - Prog *p; - uchar *cast; - long l, fl, j; - vlong o; - int i, c; - - memset(buf.dbuf, 0, n+Dbufslop); - for(p = datap; p != P; p = p->link) { - curp = p; - l = p->from.sym->value + p->from.offset - s; - c = p->from.scale; - i = 0; - if(l < 0) { - if(l+c <= 0) - continue; - while(l < 0) { - l++; - i++; - } - } - if(l >= n) - 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 = (uchar*)&fl; - if(debug['a'] && i == 0) { - Bprint(&bso, pcstr, l+s+INITDAT); - for(j=0; jto.ieee; - if(debug['a'] && i == 0) { - Bprint(&bso, pcstr, l+s+INITDAT); - for(j=0; jto.scon[j] & 0xff); - Bprint(&bso, "\t%P\n", curp); - } - for(; ito.scon[i]; - l++; - } - break; - default: - o = p->to.offset; - 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, o); - o += p->to.sym->value; - if(p->to.sym->type != STEXT && p->to.sym->type != SUNDEF) - o += INITDAT; - if(dlm) - dynreloc(p->to.sym, l+s+INITDAT, 1); - } - } - fl = o; - cast = (uchar*)&fl; - switch(c) { - default: - diag("bad nuxi %d %d\n%P", c, i, curp); - break; - case 1: - if(debug['a'] && i == 0) { - Bprint(&bso, pcstr, l+s+INITDAT); - for(j=0; jtype == STEXT) + put(s, s->name, 'T', s->value, s->size, s->version, 0); + + for(s=allsym; s!=S; s=s->allsym) { + if(s->hide) + continue; + switch(s->type&~SSUB) { + case SCONST: + case SRODATA: + case SDATA: + case SELFROSECT: + case SMACHOGOT: + case STYPE: + case SSTRING: + case SGOSTRING: + case SWINDOWS: + if(!s->reachable) + continue; + put(s, s->name, 'D', symaddr(s), s->size, s->version, s->gotype); + continue; + + case SBSS: + if(!s->reachable) + continue; + put(s, s->name, 'B', symaddr(s), s->size, s->version, s->gotype); + continue; + + case SFILE: + put(nil, s->name, 'f', s->value, 0, s->version, 0); + continue; + } + } + + for(s = textp; s != nil; s = s->next) { + if(s->text == nil) + continue; + + /* filenames first */ + for(a=s->autom; a; a=a->link) + if(a->type == D_FILE) + put(nil, a->asym->name, 'z', a->aoffset, 0, 0, 0); + else + if(a->type == D_FILE1) + put(nil, a->asym->name, 'Z', a->aoffset, 0, 0, 0); + + put(s, s->name, 'T', s->value, s->size, s->version, s->gotype); + + /* frame, auto and param after */ + put(nil, ".frame", 'm', s->text->to.offset+8, 0, 0, 0); + + for(a=s->autom; a; a=a->link) + if(a->type == D_AUTO) + put(nil, a->asym->name, 'a', -a->aoffset, 0, 0, a->gotype); + else + if(a->type == D_PARAM) + put(nil, a->asym->name, 'p', a->aoffset, 0, 0, a->gotype); + } + if(debug['v'] || debug['n']) + Bprint(&bso, "symsize = %ud\n", symsize); + Bflush(&bso); +} diff -r d8d00747375b sys/src/cmd/6l/compat.c --- a/sys/src/cmd/6l/compat.c Thu Sep 29 03:00:00 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -#include "l.h" - -/* - * fake malloc - */ -void* -malloc(ulong n) -{ - void *p; - - while(n & 7) - n++; - while(nhunk < n) - gethunk(); - p = hunk; - nhunk -= n; - hunk += n; - return p; -} - -void -free(void *p) -{ - USED(p); -} - -void* -calloc(ulong m, ulong n) -{ - void *p; - - n *= m; - p = malloc(n); - memset(p, 0, n); - return p; -} - -void* -realloc(void*, ulong) -{ - fprint(2, "realloc called\n"); - abort(); - return 0; -} - -void* -mysbrk(ulong size) -{ - return sbrk(size); -} - -void -setmalloctag(void*, ulong) -{ -} diff -r d8d00747375b sys/src/cmd/6l/l.h --- a/sys/src/cmd/6l/l.h Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/6l/l.h Mon Nov 14 17:35:25 2011 +0100 @@ -1,19 +1,51 @@ +// Inferno utils/6l/l.h +// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h +// +// 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 #include #include -#include "../6c/6.out.h" +#include "6.out.h" #ifndef EXTERN #define EXTERN extern #endif +enum +{ + thechar = '6', + PtrSize = 8 +}; + #define P ((Prog*)0) #define S ((Sym*)0) -#define TNAME (curtext?curtext->from.sym->name:noname) -#define cput(c)\ - { *cbp++ = c;\ - if(--cbc <= 0)\ - cflush(); } +#define TNAME (cursym?cursym->name:noname) typedef struct Adr Adr; typedef struct Prog Prog; @@ -21,6 +53,7 @@ typedef struct Auto Auto; typedef struct Optab Optab; typedef struct Movtab Movtab; +typedef struct Reloc Reloc; struct Adr { @@ -30,12 +63,9 @@ char u0scon[8]; Prog *u0cond; /* not used, but should be D_BRANCH */ Ieee u0ieee; + char *u0sbig; } u0; - union - { - Auto* u1autom; - Sym* u1sym; - } u1; + Sym* sym; short type; char index; char scale; @@ -45,52 +75,95 @@ #define scon u0.u0scon #define cond u0.u0cond #define ieee u0.u0ieee +#define sbig u0.u0sbig -#define autom u1.u1autom -#define sym u1.u1sym +struct Reloc +{ + int32 off; + uchar siz; + int32 type; + int64 add; + Sym* sym; +}; struct Prog { Adr from; Adr to; - Prog *forwd; + Prog* forwd; + Prog* comefrom; Prog* link; Prog* pcond; /* work on this */ vlong pc; - long line; + int32 spadj; + int32 line; + short as; + char ft; /* oclass cache */ + char tt; uchar mark; /* work on these */ uchar back; - short as; - char width; /* fake for DATA */ + char width; /* fake for DATA */ char mode; /* 16, 32, or 64 */ }; +#define datasize from.scale +#define textflag from.scale +#define iscall(p) ((p)->as == ACALL) + struct Auto { Sym* asym; Auto* link; - long aoffset; + int32 aoffset; short type; + Sym* gotype; }; struct Sym { - char *name; + char* name; short type; short version; - short become; - short frame; - uchar subtype; - ushort file; + uchar dupok; + uchar reachable; + uchar dynexport; + uchar special; + uchar stkcheck; + uchar hide; + int32 dynid; + int32 sig; + int32 plt; + int32 got; + Sym* hash; // in hash table + Sym* allsym; // in all symbol list + Sym* next; // in text or data list + Sym* sub; // in SSUB list + Sym* outer; // container of sub vlong value; - long sig; - Sym* link; + vlong size; + Sym* gotype; + char* file; + char* dynimpname; + char* dynimplib; + char* dynimpvers; + + // STEXT + Auto* autom; + Prog* text; + + // SDATA, SBSS + uchar* p; + int32 np; + int32 maxp; + Reloc* r; + int32 nr; + int32 maxr; }; struct Optab { short as; uchar* ytab; uchar prefix; - uchar op[20]; + uchar op[22]; }; struct Movtab { @@ -103,20 +176,6 @@ enum { - STEXT = 1, - SDATA, - SBSS, - SDATA1, - SXREF, - SFILE, - SCONST, - SUNDEF, - - SIMPORT, - SEXPORT, - - NHASH = 10007, - NHUNK = 100000, MINSIZ = 8, STRINGSZ = 200, MINLC = 1, @@ -159,6 +218,7 @@ Zxxx = 0, Zlit, + Zlitm_r, Z_rp, Zbr, Zcall, @@ -219,103 +279,60 @@ Rxx = 1<<1, /* extend sib index */ Rxb = 1<<0, /* extend modrm r/m, sib base, or opcode reg */ - Roffset = 22, /* no. bits for offset in relocation address */ - Rindex = 10, /* no. bits for index in relocation address */ + Maxand = 10, /* in -a output width of the byte codes */ }; -EXTERN union -{ - struct - { - char obuf[MAXIO]; /* output buffer */ - uchar ibuf[MAXIO]; /* input buffer */ - } u; - char dbuf[1]; -} buf; - -#define cbuf u.obuf -#define xbuf u.ibuf - -#pragma varargck type "A" int #pragma varargck type "A" uint #pragma varargck type "D" Adr* +#pragma varargck type "I" uchar* #pragma varargck type "P" Prog* #pragma varargck type "R" int #pragma varargck type "S" char* +#pragma varargck type "i" char* -#pragma varargck argpos diag 1 - -EXTERN long HEADR; -EXTERN long HEADTYPE; +EXTERN int32 HEADR; +EXTERN int32 HEADTYPE; +EXTERN int32 INITRND; +EXTERN vlong INITTEXT; EXTERN vlong INITDAT; -EXTERN long INITRND; -EXTERN vlong INITTEXT; EXTERN char* INITENTRY; /* entry point */ -EXTERN Biobuf bso; -EXTERN long bsssize; -EXTERN int cbc; -EXTERN char* cbp; EXTERN char* pcstr; -EXTERN int cout; EXTERN Auto* curauto; EXTERN Auto* curhist; EXTERN Prog* curp; -EXTERN Prog* curtext; -EXTERN Prog* datap; -EXTERN Prog* edatap; -EXTERN vlong datsize; +EXTERN Sym* cursym; +EXTERN Sym* datap; +EXTERN vlong elfdatsize; EXTERN char debug[128]; EXTERN char literal[32]; -EXTERN Prog* etextp; -EXTERN Prog* firstp; -EXTERN uchar fnuxi8[8]; -EXTERN uchar fnuxi4[4]; -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* hunk; -EXTERN uchar inuxi1[1]; -EXTERN uchar inuxi2[2]; -EXTERN uchar inuxi4[4]; -EXTERN uchar inuxi8[8]; +EXTERN Sym* textp; +EXTERN Sym* etextp; EXTERN char ycover[Ymax*Ymax]; EXTERN uchar* andptr; EXTERN uchar* rexptr; EXTERN uchar and[30]; EXTERN int reg[D_NONE]; EXTERN int regrex[D_NONE+1]; -EXTERN Prog* lastp; -EXTERN long lcsize; +EXTERN int32 lcsize; EXTERN int nerrors; -EXTERN long nhunk; -EXTERN long nsymbol; EXTERN char* noname; EXTERN char* outfile; EXTERN vlong pc; -EXTERN long spsize; +EXTERN char* interpreter; +EXTERN char* rpath; +EXTERN int32 spsize; EXTERN Sym* symlist; -EXTERN long symsize; -EXTERN Prog* textp; -EXTERN vlong textsize; -EXTERN long thunk; +EXTERN int32 symsize; +EXTERN int tlsoffset; EXTERN int version; EXTERN Prog zprg; EXTERN int dtype; EXTERN char* paramspace; +EXTERN Sym* adrgotype; // type symbol on last Adr read +EXTERN Sym* fromgotype; // type symbol on last p->from read -EXTERN Adr* reloca; -EXTERN int doexp, dlm; -EXTERN int imports, nimports; -EXTERN int exports, nexports; -EXTERN char* EXPTAB; -EXTERN Prog undefp; - -#define UP (&undefp) +EXTERN vlong textstksiz; +EXTERN vlong textarg; extern Optab optab[]; extern Optab* opindex[]; @@ -323,68 +340,82 @@ int Aconv(Fmt*); int Dconv(Fmt*); +int Iconv(Fmt*); int Pconv(Fmt*); int Rconv(Fmt*); int Sconv(Fmt*); -void addhist(long, int); +void addhist(int32, int); +void addstackmark(void); Prog* appendp(Prog*); void asmb(void); void asmdyn(void); void asmins(Prog*); -void asmlc(void); -void asmsp(void); void asmsym(void); +void asmelfsym(void); vlong atolwhex(char*); Prog* brchain(Prog*); Prog* brloop(Prog*); void buildop(void); -void cflush(void); -void ckoff(Sym*, long); Prog* copyp(Prog*); double cputime(void); -void datblk(long, long); +void datblk(int32, int32); +void deadcode(void); void diag(char*, ...); void dodata(void); -void doinit(void); +void doelf(void); +void domacho(void); void doprof1(void); void doprof2(void); void dostkoff(void); -void dynreloc(Sym*, ulong, int); vlong entryvalue(void); -void errorexit(void); -void export(void); -int find1(long, int); -int find2(long, int); void follow(void); void gethunk(void); -void histtoauto(void); -double ieeedtod(Ieee*); -long ieeedtof(Ieee*); -void import(void); -void ldobj(int, long, char*); -void loadlib(void); +void gotypestrings(void); void listinit(void); Sym* lookup(char*, int); -void lput(long); -void lputl(long); +void lputb(int32); +void lputl(int32); +void instinit(void); void main(int, char*[]); -void mkfwd(void); -void* mysbrk(ulong); -void nuxiinit(void); -void objfile(char*); +void* mysbrk(uint32); +Prog* newtext(Prog*, Sym*); +void nopout(Prog*); int opsize(Prog*); void patch(void); Prog* prg(void); -void readundefs(char*, int); +void parsetextconst(vlong); int relinv(int); -long reuse(Prog*, Sym*); vlong rnd(vlong, vlong); void span(void); void undef(void); -void undefsym(Sym*); -vlong vaddr(Adr*); -void wput(ushort); +vlong symaddr(Sym*); +void vputb(uint64); +void vputl(uint64); +void wputb(uint16); +void wputl(uint16); void xdefine(char*, int, vlong); -void xfol(Prog*); -int zaddr(uchar*, Adr*, Sym*[]); -void zerosig(char*); + +void machseg(char*, vlong, vlong, vlong, vlong, uint32, uint32, uint32, uint32); +void machsymseg(uint32, uint32); +void machsect(char*, char*, vlong, vlong, uint32, uint32, uint32, uint32, uint32); +void machstack(vlong); +void machdylink(void); +uint32 machheadr(void); + +/* Native is little-endian */ +#define LPUT(a) lputl(a) +#define WPUT(a) wputl(a) +#define VPUT(a) vputl(a) + +#pragma varargck type "D" Adr* +#pragma varargck type "P" Prog* +#pragma varargck type "R" int +#pragma varargck type "Z" char* +#pragma varargck type "A" int +#pragma varargck argpos diag 1 + +/* Used by ../ld/dwarf.c */ +enum +{ + DWARFREGSP = 7 +}; diff -r d8d00747375b sys/src/cmd/6l/list.c --- a/sys/src/cmd/6l/list.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/6l/list.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,4 +1,39 @@ +// Inferno utils/6l/list.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/list.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. + +// Printing. + #include "l.h" +#include "../ld/lib.h" + +static Prog* bigP; void listinit(void) @@ -9,14 +44,12 @@ fmtinstall('D', Dconv); fmtinstall('S', Sconv); fmtinstall('P', Pconv); + fmtinstall('I', Iconv); } -static Prog *bigP; - int Pconv(Fmt *fp) { - char str[STRINGSZ]; Prog *p; p = va_arg(fp->args, Prog*); @@ -24,23 +57,23 @@ switch(p->as) { case ATEXT: if(p->from.scale) { - sprint(str, "(%ld) %A %D,%d,%D", + fmtprint(fp, "(%d) %A %D,%d,%D", p->line, p->as, &p->from, p->from.scale, &p->to); break; } default: - sprint(str, "(%ld) %A %D,%D", + fmtprint(fp, "(%d) %A %D,%D", p->line, p->as, &p->from, &p->to); break; case ADATA: - case AINIT: - case ADYNT: - sprint(str, "(%ld) %A %D/%d,%D", + case AINIT_: + case ADYNT_: + fmtprint(fp, "(%d) %A %D/%d,%D", p->line, p->as, &p->from, p->from.scale, &p->to); break; } bigP = P; - return fmtstrcpy(fp, str); + return 0; } int @@ -55,26 +88,42 @@ int Dconv(Fmt *fp) { - char str[40], s[20]; + char str[STRINGSZ], s[STRINGSZ]; Adr *a; int i; a = va_arg(fp->args, Adr*); i = a->type; + + if(fp->flags & FmtLong) { + if(i != D_CONST) { + // ATEXT dst is not constant + snprint(str, sizeof(str), "!!%D", a); + goto brk; + } + parsetextconst(a->offset); + if(textarg == 0) { + snprint(str, sizeof(str), "$%lld", textstksiz); + goto brk; + } + snprint(str, sizeof(str), "$%lld-%lld", textstksiz, textarg); + goto brk; + } + if(i >= D_INDIR) { if(a->offset) - sprint(str, "%lld(%R)", a->offset, i-D_INDIR); + snprint(str, sizeof(str), "%lld(%R)", a->offset, i-D_INDIR); else - sprint(str, "(%R)", i-D_INDIR); + snprint(str, sizeof(str), "(%R)", i-D_INDIR); goto brk; } switch(i) { default: if(a->offset) - sprint(str, "$%lld,%R", a->offset, i); + snprint(str, sizeof(str), "$%lld,%R", a->offset, i); else - sprint(str, "%R", i); + snprint(str, sizeof(str), "%R", i); break; case D_NONE: @@ -84,61 +133,78 @@ case D_BRANCH: if(bigP != P && bigP->pcond != P) if(a->sym != S) - sprint(str, "%llux+%s", bigP->pcond->pc, + snprint(str, sizeof(str), "%llux+%s", bigP->pcond->pc, a->sym->name); else - sprint(str, "%llux", bigP->pcond->pc); + snprint(str, sizeof(str), "%llux", bigP->pcond->pc); else - sprint(str, "%lld(PC)", a->offset); + snprint(str, sizeof(str), "%lld(PC)", a->offset); break; case D_EXTERN: - sprint(str, "%s+%lld(SB)", a->sym->name, a->offset); + if(a->sym) { + snprint(str, sizeof(str), "%s+%lld(SB)", a->sym->name, a->offset); + break; + } + snprint(str, sizeof(str), "!!noname!!+%lld(SB)", a->offset); break; case D_STATIC: - sprint(str, "%s<%d>+%lld(SB)", a->sym->name, - a->sym->version, a->offset); + if(a->sym) { + snprint(str, sizeof(str), "%s<%d>+%lld(SB)", a->sym->name, + a->sym->version, a->offset); + break; + } + snprint(str, sizeof(str), "!!noname!!<999>+%lld(SB)", a->offset); break; case D_AUTO: - sprint(str, "%s+%lld(SP)", a->sym->name, a->offset); + if(a->sym) { + snprint(str, sizeof(str), "%s+%lld(SP)", a->sym->name, a->offset); + break; + } + snprint(str, sizeof(str), "!!noname!!+%lld(SP)", a->offset); break; case D_PARAM: - if(a->sym) - sprint(str, "%s+%lld(%s)", a->sym->name, a->offset, paramspace); - else - sprint(str, "%lld(%s)", a->offset, paramspace); + if(a->sym) { + snprint(str, sizeof(str), "%s+%lld(%s)", a->sym->name, a->offset, paramspace); + break; + } + snprint(str, sizeof(str), "!!noname!!+%lld(%s)", a->offset, paramspace); break; case D_CONST: - sprint(str, "$%lld", a->offset); + snprint(str, sizeof(str), "$%lld", a->offset); break; case D_FCONST: - sprint(str, "$(%.8lux,%.8lux)", a->ieee.h, a->ieee.l); + snprint(str, sizeof(str), "$(%.8ux,%.8ux)", a->ieee.h, a->ieee.l); break; case D_SCONST: - sprint(str, "$\"%S\"", a->scon); + snprint(str, sizeof(str), "$\"%S\"", a->scon); break; case D_ADDR: a->type = a->index; a->index = D_NONE; - sprint(str, "$%D", a); + snprint(str, sizeof(str), "$%D", a); a->index = a->type; a->type = D_ADDR; goto conv; } brk: if(a->index != D_NONE) { - sprint(s, "(%R*%d)", a->index, a->scale); + snprint(s, sizeof(s), "(%R*%d)", a->index, a->scale); strcat(str, s); } conv: - return fmtstrcpy(fp, str); + fmtstrcpy(fp, str); +// if(a->gotype) +// fmtprint(fp, "«%s»", a->gotype->name); + return 0; + } char* regstr[] = @@ -271,14 +337,14 @@ int Rconv(Fmt *fp) { - char str[20]; + char str[STRINGSZ]; int r; r = va_arg(fp->args, int); if(r >= D_AL && r <= D_NONE) - sprint(str, "%s", regstr[r-D_AL]); + snprint(str, sizeof(str), "%s", regstr[r-D_AL]); else - sprint(str, "gok(%d)", r); + snprint(str, sizeof(str), "gok(%d)", r); return fmtstrcpy(fp, str); } @@ -287,7 +353,7 @@ Sconv(Fmt *fp) { int i, c; - char str[30], *p, *a; + char str[STRINGSZ], *p, *a; a = va_arg(fp->args, char*); p = str; @@ -328,19 +394,48 @@ return fmtstrcpy(fp, str); } +int +Iconv(Fmt *fp) +{ + int i, n; + uchar *p; + char *s; + Fmt fmt; + + n = fp->prec; + fp->prec = 0; + if(!(fp->flags&FmtPrec) || n < 0) + return fmtstrcpy(fp, "%I"); + fp->flags &= ~FmtPrec; + p = va_arg(fp->args, uchar*); + + // format into temporary buffer and + // call fmtstrcpy to handle padding. + fmtstrinit(&fmt); + for(i=0; ifrom.sym != S) - tn = curtext->from.sym->name; + tn = ""; + sep = ""; + if(cursym != S) { + tn = cursym->name; + sep = ": "; + } va_start(arg, fmt); vseprint(buf, buf+sizeof(buf), fmt, arg); va_end(arg); - print("%s: %s\n", tn, buf); + print("%s%s%s\n", tn, sep, buf); nerrors++; if(nerrors > 20) { @@ -348,3 +443,16 @@ errorexit(); } } + +void +parsetextconst(vlong arg) +{ + textstksiz = arg & 0xffffffffLL; + if(textstksiz & 0x80000000LL) + textstksiz = -(-textstksiz & 0xffffffffLL); + + textarg = (arg >> 32) & 0xffffffffLL; + if(textarg & 0x80000000LL) + textarg = 0; + textarg = (textarg+7) & ~7LL; +} diff -r d8d00747375b sys/src/cmd/6l/mkenam --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/src/cmd/6l/mkenam Mon Nov 14 17:35:25 2011 +0100 @@ -0,0 +1,45 @@ +# Inferno utils/6c/mkenam +# http://code.google.com/p/inferno-os/source/browse/utils/6c/mkenam +# +# 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. + +awk ' +BEGIN { + print "char* anames[] =" + print "{" +} + +/^ A/ { + name=$1 + sub(/,/, "", name) + sub(/^A/, "", name) + print "\t\"" name "\"," +} + +END { print "};" } +' ../6l/6.out.h >enam.c diff -r d8d00747375b sys/src/cmd/6l/mkfile --- a/sys/src/cmd/6l/mkfile Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/6l/mkfile Mon Nov 14 17:35:25 2011 +0100 @@ -3,21 +3,35 @@ TARG=6l OFILES=\ asm.$O\ + data.$O\ + dwarf.$O\ + elf.$O\ + enam.$O\ + go.$O\ + ldelf.$O\ + ldmacho.$O\ + ldpe.$O\ + lib.$O\ + list.$O\ + macho.$O\ obj.$O\ optab.$O\ pass.$O\ + pe.$O\ + prof.$O\ span.$O\ - list.$O\ - enam.$O\ - compat.$O\ + symtab.$O\ HFILES=\ l.h\ - ../6c/6.out.h\ + 6.out.h\ + ../ld/dwarf.h\ + ../ld/elf.h\ + ../ld/lib.h\ + ../ld/macho.h\ BIN=/$objtype/bin CFILES=${OFILES:%.$O=%.c} -CFILES=${CFILES:enam.c=../6c/enam.c} UPDATE=\ mkfile\ $HFILES\ @@ -26,6 +40,9 @@ -#ifndef DEFAULT -#define DEFAULT '9' -#endif +char *noname = ""; +char* thestring = "amd64"; +char* paramspace = "FP"; -char *noname = ""; -char symname[] = SYMDEF; -char thechar = '6'; -char *thestring = "amd64"; -char *paramspace = "FP"; +Header headers[] = { + "plan9x32", Hplan9x32, + "plan9", Hplan9x64, + "elf", Helf, + "darwin", Hdarwin, + "linux", Hlinux, + "freebsd", Hfreebsd, + "openbsd", Hopenbsd, + "windows", Hwindows, + "windowsgui", Hwindows, + 0, 0 +}; /* - * -H2 -T0x200028 -R0x200000 is plan9 format (was -T4136 -R4096) - * -H3 -T4128 -R4096 is plan9 32-bit format - * -H5 -T0x80110000 -R4096 is ELF32 + * -Hplan9x32 -T4136 -R4096 is plan9 64-bit format + * -Hplan9 -T4128 -R4096 is plan9 32-bit format + * -Helf -T0x80110000 -R4096 is ELF32 + * -Hdarwin -Tx -Rx is apple MH-exec + * -Hlinux -Tx -Rx is linux elf-exec + * -Hfreebsd -Tx -Rx is FreeBSD elf-exec + * -Hopenbsd -Tx -Rx is OpenBSD elf-exec + * -Hwindows -Tx -Rx is MS Windows PE32+ * * options used: 189BLQSWabcjlnpsvz */ -static int -isobjfile(char *f) +void +usage(void) { - 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; + fprint(2, "usage: 6l [-options] [-E entry] [-H head] [-I interpreter] [-L dir] [-T text] [-R rnd] [-r path] [-o out] main.6\n"); + exits("usage"); } void main(int argc, char *argv[]) { - int i, c; - char *a; + int c; Binit(&bso, 1, OWRITE); - cout = -1; listinit(); memset(debug, 0, sizeof(debug)); nerrors = 0; - outfile = "6.out"; + outfile = nil; HEADTYPE = -1; INITTEXT = -1; INITDAT = -1; INITRND = -1; INITENTRY = 0; + ARGBEGIN { default: c = ARGC(); - if(c >= 0 && c < sizeof(debug)) + if(c == 'l') + usage(); + if(c >= 0 && c < sizeof(debug)) debug[c]++; break; case 'o': /* output to (next arg) */ - outfile = ARGF(); + outfile = EARGF(usage()); break; case 'E': - a = ARGF(); - if(a) - INITENTRY = a; + INITENTRY = EARGF(usage()); break; case 'H': - a = ARGF(); - if(a) - HEADTYPE = atolwhex(a); + HEADTYPE = headtype(EARGF(usage())); + break; + case 'I': + interpreter = EARGF(usage()); + break; + case 'L': + Lflag(EARGF(usage())); break; case 'T': - a = ARGF(); - if(a) - INITTEXT = atolwhex(a); + INITTEXT = atolwhex(EARGF(usage())); break; case 'D': - a = ARGF(); - if(a) - INITDAT = atolwhex(a); + INITDAT = atolwhex(EARGF(usage())); break; case 'R': - a = ARGF(); - if(a) - INITRND = atolwhex(a); + INITRND = atolwhex(EARGF(usage())); break; - case 'x': /* produce export table */ - doexp = 1; - if(argv[1] != nil && argv[1][0] != '-' && !isobjfile(argv[1])) - readundefs(ARGF(), SEXPORT); + case 'r': + rpath = EARGF(usage()); break; - case 'u': /* produce dynamically loadable module */ - dlm = 1; - debug['l']++; - if(argv[1] != nil && argv[1][0] != '-' && !isobjfile(argv[1])) - readundefs(ARGF(), SIMPORT); - break; + case 'V': + print("%cl version %s\n", thechar, getgoversion()); + errorexit(); } ARGEND - USED(argc); - if(*argv == 0) { - diag("usage: 6l [-options] objects"); - errorexit(); + + if(argc != 1) + usage(); + + mywhatsys(); // get goos + + if(HEADTYPE == -1) + HEADTYPE = headtype(goos); + + if(outfile == nil) { + if(HEADTYPE == Hwindows) + outfile = "6.out.exe"; + else + outfile = "6.out"; } - if(!debug['9'] && !debug['U'] && !debug['B']) - debug[DEFAULT] = 1; - if(HEADTYPE == -1) { - if(debug['B']) - HEADTYPE = 2; - if(debug['9']) - HEADTYPE = 2; - } + + libinit(); + switch(HEADTYPE) { default: diag("unknown -H option"); errorexit(); - case 2: /* plan 9 */ + case Hplan9x32: /* plan 9 */ HEADR = 32L+8L; if(INITTEXT == -1) - INITTEXT = 0x200000+HEADR; - if(INITDAT == -1) - INITDAT = 0; - if(INITRND == -1) - INITRND = 0x200000; - break; - case 3: /* plan 9 */ - HEADR = 32L; - if(INITTEXT == -1) INITTEXT = 4096+HEADR; if(INITDAT == -1) INITDAT = 0; if(INITRND == -1) INITRND = 4096; break; - case 5: /* elf32 executable */ - HEADR = rnd(52L+3*32L, 16); + case Hplan9x64: /* plan 9 */ + HEADR = 32L; if(INITTEXT == -1) - INITTEXT = 0xf0110000L; + INITTEXT = 4096+32; if(INITDAT == -1) INITDAT = 0; if(INITRND == -1) INITRND = 4096; break; + case Helf: /* elf32 executable */ + HEADR = rnd(52L+3*32L, 16); + if(INITTEXT == -1) + INITTEXT = 0x80110000L; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4096; + break; + case Hdarwin: /* apple MACH */ + /* + * OS X system constant - offset from 0(GS) to our TLS. + * Explained in ../../libcgo/darwin_amd64.c. + */ + tlsoffset = 0x8a0; + machoinit(); + HEADR = INITIAL_MACHO_HEADR; + if(INITRND == -1) + INITRND = 4096; + if(INITTEXT == -1) + INITTEXT = 4096+HEADR; + if(INITDAT == -1) + INITDAT = 0; + break; + case Hlinux: /* elf64 executable */ + case Hfreebsd: /* freebsd */ + case Hopenbsd: /* openbsd */ + /* + * ELF uses TLS offset negative from FS. + * Translate 0(FS) and 8(FS) into -16(FS) and -8(FS). + * Also known to ../../pkg/runtime/linux/amd64/sys.s + * and ../../libcgo/linux_amd64.s. + */ + tlsoffset = -16; + elfinit(); + HEADR = ELFRESERVE; + if(INITTEXT == -1) + INITTEXT = (1<<22)+HEADR; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4096; + break; + case Hwindows: /* PE executable */ + peinit(); + HEADR = PEFILEHEADR; + if(INITTEXT == -1) + INITTEXT = PEBASE+PESECTHEADR; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = PESECTALIGN; + break; } if(INITDAT != 0 && INITRND != 0) - print("warning: -D0x%llux is ignored because of -R0x%lux\n", + print("warning: -D0x%llux is ignored because of -R0x%ux\n", INITDAT, INITRND); if(debug['v']) - Bprint(&bso, "HEADER = -H%ld -T0x%llux -D0x%llux -R0x%lux\n", + Bprint(&bso, "HEADER = -H%d -T0x%llux -D0x%llux -R0x%ux\n", HEADTYPE, INITTEXT, INITDAT, INITRND); Bflush(&bso); - for(i=1; optab[i].as; i++) { - c = optab[i].as; - if(opindex[c] != nil) { - diag("phase error in optab: %d (%A)", i, c); - errorexit(); - } - opindex[c] = &optab[i]; - } - - for(i=0; i= D_AL && i <= D_R15B) { - reg[i] = (i-D_AL) & 7; - if(i >= D_SPB && i <= D_DIB) - regrex[i] = 0x40; - if(i >= D_R8B && i <= D_R15B) - regrex[i] = Rxr | Rxx | Rxb; - } - if(i >= D_AH && i<= D_BH) - reg[i] = 4 + ((i-D_AH) & 7); - if(i >= D_AX && i <= D_R15) { - reg[i] = (i-D_AX) & 7; - if(i >= D_R8) - regrex[i] = Rxr | Rxx | Rxb; - } - if(i >= D_F0 && i <= D_F0+7) - reg[i] = (i-D_F0) & 7; - if(i >= D_M0 && i <= D_M0+7) - reg[i] = (i-D_M0) & 7; - if(i >= D_X0 && i <= D_X0+15) { - reg[i] = (i-D_X0) & 7; - if(i >= D_X0+8) - regrex[i] = Rxr | Rxx | Rxb; - } - if(i >= D_CR+8 && i <= D_CR+15) - regrex[i] = Rxr; - } + instinit(); zprg.link = P; zprg.pcond = P; @@ -276,58 +247,22 @@ pcstr = "%.6llux "; nuxiinit(); histgen = 0; - textp = P; - datap = P; - edatap = P; pc = 0; dtype = 4; - cout = create(outfile, 1, 0775); - if(cout < 0) { - diag("cannot create %s", outfile); - errorexit(); - } version = 0; cbp = buf.cbuf; cbc = sizeof(buf.cbuf); - firstp = prg(); - lastp = firstp; - if(INITENTRY == 0) { - INITENTRY = "_main"; - if(debug['p']) - INITENTRY = "_mainp"; - if(!debug['l']) - lookup(INITENTRY, 0)->type = SXREF; - } else if(!(*INITENTRY >= '0' && *INITENTRY <= '9')) - lookup(INITENTRY, 0)->type = SXREF; - - while(*argv) - objfile(*argv++); - if(!debug['l']) - loadlib(); - firstp = firstp->link; - if(firstp == P) - errorexit(); - if(doexp || dlm){ - EXPTAB = "_exporttab"; - zerosig(EXPTAB); - zerosig("etext"); - zerosig("edata"); - zerosig("end"); - if(dlm){ - import(); - HEADTYPE = 2; - INITTEXT = 0; - INITDAT = 0; - INITRND = 8; - INITENTRY = EXPTAB; - } - export(); - } + addlibpath("command line", "command line", argv[0], "main"); + loadlib(); + deadcode(); patch(); follow(); - dodata(); + doelf(); + if(HEADTYPE == Hdarwin) + domacho(); dostkoff(); + dostkcheck(); paramspace = "SP"; /* (FP) now (SP) on output */ if(debug['p']) if(debug['1']) @@ -335,13 +270,21 @@ else doprof2(); span(); - doinit(); + if(HEADTYPE == Hwindows) + dope(); + addexport(); + textaddress(); + pclntab(); + symtab(); + dodata(); + address(); + doweak(); + reloc(); asmb(); undef(); if(debug['v']) { Bprint(&bso, "%5.2f cpu time\n", cputime()); - Bprint(&bso, "%ld symbols\n", nsymbol); - Bprint(&bso, "%ld memory used\n", thunk); + Bprint(&bso, "%d symbols\n", nsymbol); Bprint(&bso, "%d sizeof adr\n", sizeof(Adr)); Bprint(&bso, "%d sizeof prog\n", sizeof(Prog)); } @@ -350,374 +293,97 @@ errorexit(); } -void -loadlib(void) -{ - int i; - long h; - Sym *s; - -loop: - xrefresolv = 0; - for(i=0; ilink) - if(s->type == SXREF) - goto loop; +static Sym* +zsym(char *pn, Biobuf *f, Sym *h[]) +{ + int o; + + o = BGETC(f); + if(o < 0 || o >= NSYM || h[o] == nil) + mangle(pn); + return h[o]; } -void -errorexit(void) +static void +zaddr(char *pn, Biobuf *f, Adr *a, Sym *h[]) { - - if(nerrors) { - if(cout >= 0) - remove(outfile); - exits("error"); - } - exits(0); -} - -void -objfile(char *file) -{ - long off, esym, cnt, l; - int f, work; - Sym *s; - char magbuf[SARMAG]; - char name[100], pname[150]; - struct ar_hdr arhdr; - char *e, *start, *stop; - - if(file[0] == '-' && file[1] == 'l') { - if(debug['9']) - sprint(name, "/%s/lib/lib", thestring); - else - sprint(name, "/usr/%clib/lib", thechar); - strcat(name, file+2); - strcat(name, ".a"); - file = name; - } - if(debug['v']) - Bprint(&bso, "%5.2f ldobj: %s\n", cputime(), file); - Bflush(&bso); - f = open(file, 0); - if(f < 0) { - diag("cannot open file: %s", 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; - } - - 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); -} - -int -zaddr(uchar *p, Adr *a, Sym *h[]) -{ - int c, t, i; - long l; + int t; + int32 l; Sym *s; Auto *u; - t = p[0]; - c = 1; + t = BGETC(f); + a->index = D_NONE; + a->scale = 0; if(t & T_INDEX) { - a->index = p[c]; - a->scale = p[c+1]; - c += 2; - } else { - a->index = D_NONE; - a->scale = 0; + a->index = BGETC(f); + a->scale = BGETC(f); } a->offset = 0; if(t & T_OFFSET) { - /* - * Hack until Charles fixes the compiler. - a->offset = (long)(p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24)); - */ - l = p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24); - a->offset = l; - c += 4; + a->offset = Bget4(f); if(t & T_64) { - l = p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24); - a->offset = ((vlong)l<<32) | (a->offset & 0xFFFFFFFFUL); - c += 4; + a->offset &= 0xFFFFFFFFULL; + a->offset |= (vlong)Bget4(f) << 32; } } a->sym = S; - if(t & T_SYM) { - a->sym = h[p[c]]; - c++; - } + if(t & T_SYM) + a->sym = zsym(pn, f, h); a->type = D_NONE; if(t & T_FCONST) { - a->ieee.l = p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24); - a->ieee.h = p[c+4] | (p[c+5]<<8) | (p[c+6]<<16) | (p[c+7]<<24); - c += 8; + a->ieee.l = Bget4(f); + a->ieee.h = Bget4(f); a->type = D_FCONST; } else if(t & T_SCONST) { - for(i=0; iscon[i] = p[c+i]; - c += NSNAME; + Bread(f, a->scon, NSNAME); a->type = D_SCONST; } - if(t & T_TYPE) { - a->type = p[c]; - c++; + if(t & T_TYPE) + a->type = BGETC(f); + if(a->type < 0 || a->type >= D_SIZE) + mangle(pn); + adrgotype = S; + if(t & T_GOTYPE) + adrgotype = zsym(pn, f, h); + s = a->sym; + t = a->type; + if(t == D_INDIR+D_GS) + a->offset += tlsoffset; + if(t != D_AUTO && t != D_PARAM) { + if(s && adrgotype) + s->gotype = adrgotype; + return; } - s = a->sym; - if(s == S) - return c; - - t = a->type; - if(t != D_AUTO && t != D_PARAM) - return c; l = a->offset; for(u=curauto; u; u=u->link) { if(u->asym == s) if(u->type == t) { if(u->aoffset > l) u->aoffset = l; - return c; + if(adrgotype) + u->gotype = adrgotype; + return; } } + + switch(t) { + case D_FILE: + case D_FILE1: + case D_AUTO: + case D_PARAM: + if(s == S) + mangle(pn); + } - while(nhunk < sizeof(Auto)) - gethunk(); - u = (Auto*)hunk; - nhunk -= sizeof(Auto); - hunk += sizeof(Auto); - + u = mal(sizeof(*u)); u->link = curauto; curauto = u; u->asym = s; u->aoffset = l; u->type = t; - return c; -} - -void -addlib(char *obj) -{ - char name[1024], comp[256], *p; - int i; - - if(histfrogp <= 0) - return; - - if(histfrog[0]->name[1] == '/') { - sprint(name, ""); - i = 1; - } else - if(histfrog[0]->name[1] == '.') { - sprint(name, "."); - i = 0; - } else { - if(debug['9']) - sprint(name, "/%s/lib", thestring); - else - sprint(name, "/usr/%clib", thechar); - i = 0; - } - - 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(name) + strlen(comp) + 3 >= sizeof(name)) { - diag("library component too long"); - return; - } - strcat(name, "/"); - strcat(name, comp); - } - 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) { - 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; + u->gotype = adrgotype; } void @@ -728,47 +394,24 @@ p->to.type = D_NONE; } -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; -} - void -ldobj(int f, long c, char *pn) +ldobj1(Biobuf *f, char *pkg, int64 len, char *pn) { vlong ipc; - Prog *p, *t; - uchar *bloc, *bsize, *stop; + Prog *p; int v, o, r, skip, mode; - Sym *h[NSYM], *s, *di; - ulong sig; - static int files; - static char **filen; - char **nfilen; + Sym *h[NSYM], *s; + uint32 sig; + char *name, *x; + int ntext; + vlong eof; + char src[1024]; + Prog *lastp; - if((files&15) == 0){ - nfilen = malloc((files+16)*sizeof(char*)); - memmove(nfilen, filen, files*sizeof(char*)); - free(filen); - filen = nfilen; - } - filen[files++] = strdup(pn); - - bsize = buf.xbuf; - bloc = buf.xbuf; - di = S; + lastp = nil; + ntext = 0; + eof = Boffset(f) + len; + src[0] = 0; newloop: memset(h, 0, sizeof(h)); @@ -779,67 +422,57 @@ mode = 64; loop: - if(c <= 0) + if(f->state == Bracteof || Boffset(f) >= eof) goto eof; - r = bsize - bloc; - if(r < 100 && r < c) { /* enough for largest prog */ - bsize = readsome(f, buf.xbuf, bloc, bsize, c); - if(bsize == 0) - goto eof; - bloc = buf.xbuf; - goto loop; - } - o = bloc[0] | (bloc[1] << 8); + o = BGETC(f); + if(o == Beof) + goto eof; + o |= BGETC(f) << 8; if(o <= AXXX || o >= ALAST) { if(o < 0) goto eof; - diag("%s: opcode out of range %d", pn, o); + diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o); print(" probably not a .6 file\n"); errorexit(); } if(o == ANAME || o == ASIGNAME) { sig = 0; - if(o == ASIGNAME) { - sig = bloc[2] | (bloc[3]<<8) | (bloc[4]<<16) | (bloc[5]<<24); - bloc += 4; - c -= 4; - } - stop = memchr(&bloc[4], 0, bsize-&bloc[4]); - if(stop == 0){ - bsize = readsome(f, buf.xbuf, bloc, bsize, c); - if(bsize == 0) - goto eof; - bloc = buf.xbuf; - stop = memchr(&bloc[4], 0, bsize-&bloc[4]); - if(stop == 0){ + if(o == ASIGNAME) + sig = Bget4(f); + v = BGETC(f); /* type */ + o = BGETC(f); /* sym */ + r = 0; + if(v == D_STATIC) + r = version; + name = Brdline(f, '\0'); + if(name == nil) { + if(Blinelen(f) > 0) { fprint(2, "%s: name too long\n", pn); errorexit(); } + goto eof; } - v = bloc[2]; /* type */ - o = bloc[3]; /* sym */ - bloc += 4; - c -= 4; - - r = 0; - if(v == D_STATIC) - r = version; - s = lookup((char*)bloc, r); - c -= &stop[1] - bloc; - bloc = stop + 1; + x = expandpkg(name, pkg); + s = lookup(x, r); + if(x != name) + free(x); if(debug['S'] && r == 0) sig = 1729; if(sig != 0){ if(s->sig != 0 && s->sig != sig) - diag("incompatible type signatures %lux(%s) and %lux(%s) for %s", s->sig, filen[s->file], sig, pn, s->name); + diag("incompatible type signatures" + "%ux(%s) and %ux(%s) for %s", + s->sig, s->file, sig, pn, s->name); s->sig = sig; - s->file = files-1; + s->file = pn; } if(debug['W']) print(" ANAME %s\n", s->name); + if(o < 0 || o >= nelem(h)) + mangle(pn); h[o] = s; if((v == D_EXTERN || v == D_STATIC) && s->type == 0) s->type = SXREF; @@ -854,24 +487,30 @@ histfrogp++; } else collapsefrog(s); + dwarfaddfrag(s->value, s->name); } goto loop; } - while(nhunk < sizeof(Prog)) - gethunk(); - p = (Prog*)hunk; - nhunk -= sizeof(Prog); - hunk += sizeof(Prog); - + p = mal(sizeof(*p)); p->as = o; - p->line = bloc[2] | (bloc[3] << 8) | (bloc[4] << 16) | (bloc[5] << 24); + p->line = Bget4(f); p->back = 2; p->mode = mode; - r = zaddr(bloc+6, &p->from, h) + 6; - r += zaddr(bloc+r, &p->to, h); - bloc += r; - c -= r; + p->ft = 0; + p->tt = 0; + zaddr(pn, f, &p->from, h); + fromgotype = adrgotype; + zaddr(pn, f, &p->to, h); + + switch(p->as) { + case ATEXT: + case ADATA: + case AGLOBL: + if(p->from.sym == S) + mangle(pn); + break; + } if(debug['W']) print("%P\n", p); @@ -879,10 +518,12 @@ switch(p->as) { case AHISTORY: if(p->to.offset == -1) { - addlib(pn); + addlib(src, pn); histfrogp = 0; goto loop; } + if(src[0] == '\0') + copyhistfrog(src, sizeof src); addhist(p->line, D_FILE); /* 'z' */ if(p->to.offset) addhist(p->to.offset, D_FILE1); /* 'Z' */ @@ -891,79 +532,53 @@ case AEND: histtoauto(); - if(curtext != P) - curtext->to.autom = curauto; + if(cursym != nil && cursym->text) + cursym->autom = curauto; curauto = 0; - curtext = P; - if(c) - goto newloop; - return; + cursym = nil; + if(Boffset(f) == eof) + return; + goto newloop; case AGLOBL: s = p->from.sym; if(s->type == 0 || s->type == SXREF) { s->type = SBSS; - s->value = 0; + s->size = 0; } - if(s->type != SBSS) { + if(s->type != SBSS && !s->dupok) { diag("%s: redefinition: %s in %s", pn, s->name, TNAME); s->type = SBSS; - s->value = 0; + s->size = 0; } - if(p->to.offset > s->value) - s->value = p->to.offset; + if(p->to.offset > s->size) + s->size = p->to.offset; + if(p->from.scale & DUPOK) + s->dupok = 1; + if(p->from.scale & RODATA) + s->type = SRODATA; goto loop; - case ADYNT: - if(p->to.sym == S) { - diag("DYNT without a sym\n%P", p); - break; + case ADATA: + // Assume that AGLOBL comes after ADATA. + // If we've seen an AGLOBL that said this sym was DUPOK, + // ignore any more ADATA we see, which must be + // redefinitions. + s = p->from.sym; + if(s->dupok) { +// if(debug['v']) +// Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn); + goto loop; } - di = p->to.sym; - p->from.scale = 4; - if(di->type == SXREF) { - if(debug['z']) - Bprint(&bso, "%P set to %d\n", p, dtype); - di->type = SCONST; - di->value = dtype; - dtype += 4; + if(s->file == nil) + s->file = pn; + else if(s->file != pn) { + diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn); + errorexit(); } - if(p->from.sym == S) - break; - - p->from.offset = di->value; - p->from.sym->type = SDATA; - if(curtext == P) { - diag("DYNT not in text: %P", p); - break; - } - p->to.sym = curtext->from.sym; - p->to.type = D_ADDR; - p->to.index = D_EXTERN; - goto data; - - case AINIT: - if(p->from.sym == S) { - diag("INIT without a sym\n%P", p); - break; - } - if(di == S) { - diag("INIT without previous DYNT\n%P", p); - break; - } - p->from.offset = di->value; - p->from.sym->type = SDATA; - goto data; - - case ADATA: - data: - if(edatap == P) - datap = p; - else - edatap->link = p; - edatap = p; - p->link = P; + savedata(s, p, pn); + unmal(p, sizeof *p); goto loop; case AGOK: @@ -972,18 +587,30 @@ goto loop; case ATEXT: - if(curtext != P) { + s = p->from.sym; + if(s->text != nil) { + diag("%s: %s: redefinition", pn, s->name); + return; + } + if(ntext++ == 0 && s->type != 0 && s->type != SXREF) { + /* redefinition, so file has probably been seen before */ + if(debug['v']) + Bprint(&bso, "skipping: %s: redefinition: %s", pn, s->name); + return; + } + if(cursym != nil && cursym->text) { histtoauto(); - curtext->to.autom = curauto; + cursym->autom = curauto; curauto = 0; } skip = 0; - curtext = p; - s = p->from.sym; - if(s == S) { - diag("%s: no TEXT symbol: %P", pn, p); - errorexit(); - } + if(etextp) + etextp->next = s; + else + textp = s; + etextp = s; + s->text = p; + cursym = s; if(s->type != 0 && s->type != SXREF) { if(p->from.scale & DUPOK) { skip = 1; @@ -991,19 +618,15 @@ } diag("%s: redefinition: %s\n%P", pn, s->name, p); } + if(fromgotype) { + if(s->gotype && s->gotype != fromgotype) + diag("%s: type mismatch for %s", pn, s->name); + s->gotype = fromgotype; + } s->type = STEXT; s->value = pc; - lastp->link = p; lastp = p; - p->pc = pc; - pc++; - if(textp == P) { - textp = p; - etextp = p; - goto loop; - } - etextp->pcond = p; - etextp = p; + p->pc = pc++; goto loop; case AMODE: @@ -1036,24 +659,12 @@ goto casdef; if(p->from.type == D_FCONST) { /* size sb 9 max */ - sprint(literal, "$%lux", ieeedtof(&p->from.ieee)); + sprint(literal, "$%ux", ieeedtof(&p->from.ieee)); s = lookup(literal, 0); if(s->type == 0) { - s->type = SBSS; - s->value = 4; - t = prg(); - t->as = ADATA; - t->line = p->line; - t->from.type = D_EXTERN; - t->from.sym = s; - t->from.scale = 4; - t->to = p->from; - if(edatap == P) - datap = t; - else - edatap->link = t; - edatap = t; - t->link = P; + s->type = SDATA; + adduint32(s, ieeedtof(&p->from.ieee)); + s->reachable = 0; } p->from.type = D_EXTERN; p->from.sym = s; @@ -1081,25 +692,14 @@ goto casdef; if(p->from.type == D_FCONST) { /* size sb 18 max */ - sprint(literal, "$%lux.%lux", + sprint(literal, "$%ux.%ux", p->from.ieee.l, p->from.ieee.h); s = lookup(literal, 0); if(s->type == 0) { - s->type = SBSS; - s->value = 8; - t = prg(); - t->as = ADATA; - t->line = p->line; - t->from.type = D_EXTERN; - t->from.sym = s; - t->from.scale = 8; - t->to = p->from; - if(edatap == P) - datap = t; - else - edatap->link = t; - edatap = t; - t->link = P; + s->type = SDATA; + adduint32(s, p->from.ieee.l); + adduint32(s, p->from.ieee.h); + s->reachable = 0; } p->from.type = D_EXTERN; p->from.sym = s; @@ -1111,70 +711,31 @@ default: if(skip) nopout(p); + p->pc = pc; + pc++; if(p->to.type == D_BRANCH) p->to.offset += ipc; + if(lastp == nil) { + if(p->as != ANOP) + diag("unexpected instruction: %P", p); + goto loop; + } lastp->link = p; lastp = p; - p->pc = pc; - pc++; goto loop; } - goto loop; eof: diag("truncated object file: %s", pn); } -Sym* -lookup(char *symb, int v) -{ - Sym *s; - char *p; - long h; - int l, c; - - 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; - - while(nhunk < sizeof(Sym)) - gethunk(); - s = (Sym*)hunk; - nhunk -= sizeof(Sym); - hunk += 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; - nsymbol++; - return s; -} - Prog* prg(void) { Prog *p; - while(nhunk < sizeof(Prog)) - gethunk(); - p = (Prog*)hunk; - nhunk -= sizeof(Prog); - hunk += sizeof(Prog); + p = mal(sizeof(*p)); *p = zprg; return p; @@ -1202,394 +763,3 @@ p->mode = q->mode; return p; } - -void -gethunk(void) -{ - char *h; - long nh; - - nh = NHUNK; - if(thunk >= 5L*NHUNK) { - nh = 5L*NHUNK; - if(thunk >= 25L*NHUNK) - nh = 25L*NHUNK; - } - h = mysbrk(nh); - if(h == (char*)-1) { - diag("out of memory"); - errorexit(); - } - hunk = h; - nhunk = nh; - thunk += nh; -} - -void -doprof1(void) -{ - Sym *s; - long n; - Prog *p, *q; - - if(debug['v']) - Bprint(&bso, "%5.2f profile 1\n", cputime()); - Bflush(&bso); - s = lookup("__mcount", 0); - n = 1; - for(p = firstp->link; p != P; p = p->link) { - if(p->as == ATEXT) { - q = prg(); - q->line = p->line; - q->link = datap; - datap = q; - q->as = ADATA; - q->from.type = D_EXTERN; - q->from.offset = n*4; - q->from.sym = s; - q->from.scale = 4; - q->to = p->from; - q->to.type = D_CONST; - - q = prg(); - q->line = p->line; - q->pc = p->pc; - q->link = p->link; - p->link = q; - p = q; - p->as = AADDL; - p->from.type = D_CONST; - p->from.offset = 1; - p->to.type = D_EXTERN; - p->to.sym = s; - p->to.offset = n*4 + 4; - - n += 2; - continue; - } - } - q = prg(); - q->line = 0; - q->link = datap; - datap = q; - - q->as = ADATA; - q->from.type = D_EXTERN; - q->from.sym = s; - q->from.scale = 4; - q->to.type = D_CONST; - q->to.offset = n; - - s->type = SBSS; - s->value = n*4; -} - -void -doprof2(void) -{ - Sym *s2, *s4; - Prog *p, *q, *q2, *ps2, *ps4; - - if(debug['v']) - Bprint(&bso, "%5.2f profile 2\n", cputime()); - Bflush(&bso); - - if(debug['e']){ - s2 = lookup("_tracein", 0); - s4 = lookup("_traceout", 0); - }else{ - s2 = lookup("_profin", 0); - s4 = lookup("_profout", 0); - } - if(s2->type != STEXT || s4->type != STEXT) { - if(debug['e']) - diag("_tracein/_traceout not defined %d %d", s2->type, s4->type); - else - diag("_profin/_profout not defined"); - return; - } - - ps2 = P; - ps4 = P; - for(p = firstp; p != P; p = p->link) { - if(p->as == ATEXT) { - if(p->from.sym == s2) { - p->from.scale = 1; - ps2 = p; - } - if(p->from.sym == s4) { - p->from.scale = 1; - ps4 = p; - } - } - } - for(p = firstp; p != P; p = p->link) { - if(p->as == ATEXT) { - curtext = p; - - if(p->from.scale & NOPROF) { /* dont profile */ - for(;;) { - q = p->link; - if(q == P) - break; - if(q->as == ATEXT) - break; - p = q; - } - continue; - } - - /* - * JMPL profin - */ - q = prg(); - q->line = p->line; - q->pc = p->pc; - q->link = p->link; - if(debug['e']){ /* embedded tracing */ - q2 = prg(); - p->link = q2; - q2->link = q; - - q2->line = p->line; - q2->pc = p->pc; - - q2->as = AJMP; - q2->to.type = D_BRANCH; - q2->to.sym = p->to.sym; - q2->pcond = q->link; - }else - p->link = q; - p = q; - p->as = ACALL; - p->to.type = D_BRANCH; - p->pcond = ps2; - p->to.sym = s2; - - continue; - } - if(p->as == ARET) { - /* - * RET (default) - */ - if(debug['e']){ /* embedded tracing */ - q = prg(); - q->line = p->line; - q->pc = p->pc; - q->link = p->link; - p->link = q; - p = q; - } - /* - * RET - */ - q = prg(); - q->as = ARET; - q->from = p->from; - q->to = p->to; - q->link = p->link; - p->link = q; - - /* - * JAL profout - */ - p->as = ACALL; - p->from = zprg.from; - p->to = zprg.to; - p->to.type = D_BRANCH; - p->pcond = ps4; - p->to.sym = s4; - - p = q; - - continue; - } - } -} - -void -nuxiinit(void) -{ - int i, c; - - for(i=0; i<4; i++) { - c = find1(0x04030201L, i+1); - if(i < 2) - inuxi2[i] = c; - if(i < 1) - inuxi1[i] = c; - inuxi4[i] = c; - inuxi8[i] = c; - inuxi8[i+4] = c+4; - fnuxi4[i] = c; - fnuxi8[i] = c; - fnuxi8[i+4] = c+4; - } - if(debug['v']) { - Bprint(&bso, "inuxi = "); - for(i=0; i<1; i++) - Bprint(&bso, "%d", inuxi1[i]); - Bprint(&bso, " "); - for(i=0; i<2; i++) - Bprint(&bso, "%d", inuxi2[i]); - Bprint(&bso, " "); - for(i=0; i<4; i++) - Bprint(&bso, "%d", inuxi4[i]); - Bprint(&bso, " "); - for(i=0; i<8; i++) - Bprint(&bso, "%d", inuxi8[i]); - Bprint(&bso, "\nfnuxi = "); - for(i=0; i<4; i++) - Bprint(&bso, "%d", fnuxi4[i]); - Bprint(&bso, " "); - for(i=0; i<8; i++) - Bprint(&bso, "%d", fnuxi8[i]); - Bprint(&bso, "\n"); - } - Bflush(&bso); -} - -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; -} - -int -find2(long l, int c) -{ - short *p; - int i; - - p = (short*)&l; - for(i=0; i<4; i+=2) { - if(((*p >> 8) & 0xff) == c) - return i; - if((*p++ & 0xff) == c) - return i+1; - } - return 0; -} - -long -ieeedtof(Ieee *e) -{ - int exp; - long v; - - if(e->h == 0) - return 0; - exp = (e->h>>20) & ((1L<<11)-1L); - exp -= (1L<<10) - 2L; - v = (e->h & 0xfffffL) << 3; - v |= (e->l >> 29) & 0x7L; - if((e->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 |= e->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); -} - -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 -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); -} diff -r d8d00747375b sys/src/cmd/6l/optab.c --- a/sys/src/cmd/6l/optab.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/6l/optab.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,3 +1,33 @@ +// Inferno utils/6l/optab.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/optab.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" uchar ynone[] = @@ -7,7 +37,7 @@ }; uchar ytext[] = { - Ymb, Yi32, Zpseudo,1, + Ymb, Yi64, Zpseudo,1, 0 }; uchar ynop[] = @@ -170,7 +200,8 @@ Ymm, Ymr, Zm_r_xm, 1, // MMX MOVD Ymr, Ymm, Zr_m_xm, 1, // MMX MOVD Yxr, Ymr, Zm_r_xm_nr, 2, // MOVDQ2Q - Yxr, Ym, Zr_m_xm_nr, 2, // MOVQ xmm store + Yxm, Yxr, Zm_r_xm_nr, 2, // MOVQ xmm1/m64 -> xmm2 + Yxr, Yxm, Zr_m_xm_nr, 2, // MOVQ xmm1 -> xmm2/m64 Yml, Yxr, Zm_r_xm, 2, // MOVD xmm load Yxr, Yml, Zr_m_xm, 2, // MOVD xmm store Yiauto, Yrl, Zaut_r, 2, // built-in LEAQ @@ -499,7 +530,69 @@ Ymr, Yrl, Zm_r_xm, 1, 0 }; +uchar ycrc32l[] = +{ + Yml, Yrl, Zlitm_r, 0, +}; +/* + * You are doasm, holding in your hand a Prog* with p->as set to, say, ACRC32, + * and p->from and p->to as operands (Adr*). The linker scans optab to find + * the entry with the given p->as and then looks through the ytable for that + * instruction (the second field in the optab struct) for a line whose first + * two values match the Ytypes of the p->from and p->to operands. The function + * oclass in span.c computes the specific Ytype of an operand and then the set + * of more general Ytypes that it satisfies is implied by the ycover table, set + * up in instinit. For example, oclass distinguishes the constants 0 and 1 + * from the more general 8-bit constants, but instinit says + * + * ycover[Yi0*Ymax + Ys32] = 1; + * ycover[Yi1*Ymax + Ys32] = 1; + * ycover[Yi8*Ymax + Ys32] = 1; + * + * which means that Yi0, Yi1, and Yi8 all count as Ys32 (signed 32) + * if that's what an instruction can handle. + * + * In parallel with the scan through the ytable for the appropriate line, there + * is a z pointer that starts out pointing at the strange magic byte list in + * the Optab struct. With each step past a non-matching ytable line, z + * advances by the 4th entry in the line. When a matching line is found, that + * z pointer has the extra data to use in laying down the instruction bytes. + * The actual bytes laid down are a function of the 3rd entry in the line (that + * is, the Ztype) and the z bytes. + * + * For example, let's look at AADDL. The optab line says: + * { AADDL, yaddl, Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 }, + * + * and yaddl says + * uchar yaddl[] = + * { + * Yi8, Yml, Zibo_m, 2, + * Yi32, Yax, Zil_, 1, + * Yi32, Yml, Zilo_m, 2, + * Yrl, Yml, Zr_m, 1, + * Yml, Yrl, Zm_r, 1, + * 0 + * }; + * + * so there are 5 possible types of ADDL instruction that can be laid down, and + * possible states used to lay them down (Ztype and z pointer, assuming z + * points at {0x83,(00),0x05,0x81,(00),0x01,0x03}) are: + * + * Yi8, Yml -> Zibo_m, z (0x83, 00) + * Yi32, Yax -> Zil_, z+2 (0x05) + * Yi32, Yml -> Zilo_m, z+2+1 (0x81, 0x00) + * Yrl, Yml -> Zr_m, z+2+1+2 (0x01) + * Yml, Yrl -> Zm_r, z+2+1+2+1 (0x03) + * + * The Pconstant in the optab line controls the prefix bytes to emit. That's + * relatively straightforward as this program goes. + * + * The switch on t[2] in doasm implements the various Z cases. Zibo_m, for + * example, is an opcode byte (z[0]) then an asmando (which is some kind of + * encoded addressing mode for the Yml arg), and then a single immediate byte. + * Zilo_m is the same but a long (32-bit) immediate. + */ Optab optab[] = /* as, ytab, andproto, opcode */ { @@ -696,7 +789,8 @@ { AIRETW, ynone, Pe, 0xcf }, { AJCC, yjcond, Px, 0x73,0x83,(00) }, { AJCS, yjcond, Px, 0x72,0x82 }, - { AJCXZ, yloop, Px, 0xe3 }, + { AJCXZL, yloop, Px, 0xe3 }, + { AJCXZQ, yloop, Px, 0xe3 }, { AJEQ, yjcond, Px, 0x74,0x84 }, { AJGE, yjcond, Px, 0x7d,0x8d }, { AJGT, yjcond, Px, 0x7f,0x8f }, @@ -753,7 +847,7 @@ { AMOVBWSX, ymb_rl, Pq, 0xbe }, { AMOVBWZX, ymb_rl, Pq, 0xb6 }, { AMOVO, yxmov, Pe, 0x6f,0x7f }, - { AMOVOU, yxmov, Pf2, 0x6f,0x7f }, + { AMOVOU, yxmov, Pf3, 0x6f,0x7f }, { AMOVHLPS, yxr, Pm, 0x12 }, { AMOVHPD, yxmov, Pe, 0x16,0x17 }, { AMOVHPS, yxmov, Pm, 0x16,0x17 }, @@ -762,14 +856,14 @@ { AMOVLPD, yxmov, Pe, 0x12,0x13 }, { AMOVLPS, yxmov, Pm, 0x12,0x13 }, { AMOVLQSX, yml_rl, Pw, 0x63 }, - { AMOVLQZX, yml_rl, Px, 0x63 }, + { AMOVLQZX, yml_rl, Px, 0x8b }, { AMOVMSKPD, yxrrl, Pq, 0x50 }, { AMOVMSKPS, yxrrl, Pm, 0x50 }, { AMOVNTO, yxr_ml, Pe, 0xe7 }, { AMOVNTPD, yxr_ml, Pe, 0x2b }, { AMOVNTPS, yxr_ml, Pm, 0x2b }, { AMOVNTQ, ymr_ml, Pm, 0xe7 }, - { AMOVQ, ymovq, Pw, 0x89,0x8b,0x31,0xc7,(00),0xb8,0xc7,(00),0x6f,0x7f,0x6e,0x7e,Pf2,0xd6,Pe,0xd6,Pe,0x6e,Pe,0x7e }, + { AMOVQ, ymovq, Pw, 0x89, 0x8b, 0x31, 0xc7,(00), 0xb8, 0xc7,(00), 0x6f, 0x7f, 0x6e, 0x7e, Pf2,0xd6, Pf3,0x7e, Pe,0xd6, Pe,0x6e, Pe,0x7e }, { AMOVQOZX, ymrxr, Pf3, 0xd6,0x7e }, { AMOVSB, ynone, Pb, 0xa4 }, { AMOVSD, yxmov, Pf2, 0x10,0x11 }, @@ -827,6 +921,7 @@ { APADDW, ymm, Py, 0xfd,Pe,0xfd }, { APAND, ymm, Py, 0xdb,Pe,0xdb }, { APANDN, ymm, Py, 0xdf,Pe,0xdf }, + { APAUSE, ynone, Px, 0xf3,0x90 }, { APAVGB, ymm, Py, 0xe0,Pe,0xe0 }, { APAVGW, ymm, Py, 0xe3,Pe,0xe3 }, { APCMPEQB, ymm, Py, 0x74,Pe,0x74 }, @@ -877,14 +972,14 @@ { APOPQ, ypopl, Py, 0x58,0x8f,(00) }, { APOPW, ypopl, Pe, 0x58,0x8f,(00) }, { APOR, ymm, Py, 0xeb,Pe,0xeb }, - { APSADBW, yxm, Pw, Pe,0xf6 }, + { APSADBW, yxm, Pq, 0xf6 }, { APSHUFHW, yxshuf, Pf3, 0x70 }, - { APSHUFL, yxm, Pw, Pe,0x70 }, + { APSHUFL, yxshuf, Pq, 0x70 }, { APSHUFLW, yxshuf, Pf2, 0x70 }, { APSHUFW, ymshuf, Pm, 0x70 }, { APSLLO, ypsdq, Pq, 0x73,(07) }, { APSLLL, yps, Py, 0xf2, 0x72,(06), Pe,0xf2, Pe,0x72,(06) }, - { APSLLQ, yps, Py, 0xf3, 0x73,(06), Pe,0xf3, Pe,0x7e,(06) }, + { APSLLQ, yps, Py, 0xf3, 0x73,(06), Pe,0xf3, Pe,0x73,(06) }, { APSLLW, yps, Py, 0xf1, 0x71,(06), Pe,0xf1, Pe,0x71,(06) }, { APSRAL, yps, Py, 0xe2, 0x72,(04), Pe,0xe2, Pe,0x72,(04) }, { APSRAW, yps, Py, 0xe1, 0x71,(04), Pe,0xe1, Pe,0x71,(04) }, @@ -1169,6 +1264,9 @@ { AXADDQ, yrl_ml, Pw, 0x0f,0xc1 }, { AXADDW, yrl_ml, Pe, 0x0f,0xc1 }, + { ACRC32B, ycrc32l,Px, 0xf2,0x0f,0x38,0xf0,0}, + { ACRC32Q, ycrc32l,Pw, 0xf2,0x0f,0x38,0xf1,0}, + { AEND }, 0 }; diff -r d8d00747375b sys/src/cmd/6l/pass.c --- a/sys/src/cmd/6l/pass.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/6l/pass.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,107 +1,40 @@ +// Inferno utils/6l/pass.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/pass.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. + +// Code and data passes. + #include "l.h" +#include "../ld/lib.h" +#include "../ld/stack.h" -void -dodata(void) -{ - int i; - Sym *s; - Prog *p; - long t, u; - - 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); - t = p->from.offset + p->width; - if(t > s->value) - diag("initialize bounds (%lld): %s\n%P", - s->value, s->name, p); - } - /* allocate small guys */ - datsize = 0; - for(i=0; ilink) { - if(s->type != SDATA) - if(s->type != SBSS) - continue; - t = s->value; - if(t == 0) { - diag("%s: no size", s->name); - t = 1; - } - t = rnd(t, 4); - s->value = t; - if(t > MINSIZ) - continue; - if(t >= 8) - datsize = rnd(datsize, 8); - s->value = datsize; - datsize += t; - s->type = SDATA1; - } - - /* allocate the rest of the data */ - for(i=0; ilink) { - if(s->type != SDATA) { - if(s->type == SDATA1) - s->type = SDATA; - continue; - } - t = s->value; - if(t >= 8) - datsize = rnd(datsize, 8); - s->value = datsize; - datsize += t; - } - if(datsize) - datsize = rnd(datsize, 8); - - if(debug['j']) { - /* - * pad data with bss that fits up to next - * 8k boundary, then push data to 8k - */ - u = rnd(datsize, 8192); - u -= datsize; - for(i=0; ilink) { - if(s->type != SBSS) - continue; - t = s->value; - if(t > u) - continue; - u -= t; - s->value = datsize; - s->type = SDATA; - datsize += t; - } - datsize += u; - } - - /* now the bss */ - bsssize = 0; - for(i=0; ilink) { - if(s->type != SBSS) - continue; - t = s->value; - if(t >= 8) - bsssize = rnd(bsssize, 8); - s->value = bsssize + datsize; - bsssize += t; - } - xdefine("edata", SBSS, datsize); - xdefine("end", SBSS, bsssize + datsize); -} +static void xfol(Prog*, Prog**); Prog* brchain(Prog *p) @@ -119,19 +52,61 @@ void follow(void) { + Prog *firstp, *lastp; if(debug['v']) Bprint(&bso, "%5.2f follow\n", cputime()); Bflush(&bso); - firstp = prg(); - lastp = firstp; - xfol(textp); - lastp->link = P; - firstp = firstp->link; + + for(cursym = textp; cursym != nil; cursym = cursym->next) { + firstp = prg(); + lastp = firstp; + xfol(cursym->text, &lastp); + lastp->link = nil; + cursym->text = firstp->link; + } } -void -xfol(Prog *p) +static int +nofollow(int a) +{ + switch(a) { + case AJMP: + case ARET: + case AIRETL: + case AIRETQ: + case AIRETW: + case ARETFL: + case ARETFQ: + case ARETFW: + return 1; + } + return 0; +} + +static int +pushpop(int a) +{ + switch(a) { + case APUSHL: + case APUSHFL: + case APUSHQ: + case APUSHFQ: + case APUSHW: + case APUSHFW: + case APOPL: + case APOPFL: + case APOPQ: + case APOPFQ: + case APOPW: + case APOPFW: + return 1; + } + return 0; +} + +static void +xfol(Prog *p, Prog **last) { Prog *q; int i; @@ -140,51 +115,31 @@ loop: if(p == P) return; - if(p->as == ATEXT) - curtext = p; if(p->as == AJMP) - if((q = p->pcond) != P) { + if((q = p->pcond) != P && q->as != ATEXT) { + /* mark instruction as done and continue layout at target of jump */ p->mark = 1; p = q; if(p->mark == 0) goto loop; } if(p->mark) { - /* copy up to 4 instructions to avoid branch */ + /* + * p goes here, but already used it elsewhere. + * copy up to 4 instructions or else branch to other copy. + */ for(i=0,q=p; i<4; i++,q=q->link) { if(q == P) break; - if(q == lastp) + if(q == *last) break; a = q->as; if(a == ANOP) { i--; continue; } - switch(a) { - case AJMP: - case ARET: - case AIRETL: - case AIRETQ: - case AIRETW: - case ARETFL: - case ARETFQ: - case ARETFW: - - case APUSHL: - case APUSHFL: - case APUSHQ: - case APUSHFQ: - case APUSHW: - case APUSHFW: - case APOPL: - case APOPFL: - case APOPQ: - case APOPFQ: - case APOPW: - case APOPFW: - goto brk; - } + if(nofollow(a) || pushpop(a)) + break; // NOTE(rsc): arm does goto copy if(q->pcond == P || q->pcond->mark) continue; if(a == ACALL || a == ALOOP) @@ -197,8 +152,8 @@ q = copyp(p); p = p->link; q->mark = 1; - lastp->link = q; - lastp = q; + (*last)->link = q; + *last = q; if(q->as != a || q->pcond == P || q->pcond->mark) continue; @@ -206,14 +161,13 @@ p = q->pcond; q->pcond = q->link; q->link = p; - xfol(q->link); + xfol(q->link, last); p = q->link; if(p->mark) return; goto loop; } } /* */ - brk:; q = prg(); q->as = AJMP; q->line = p->line; @@ -222,15 +176,22 @@ q->pcond = p; p = q; } + + /* emit p */ p->mark = 1; - lastp->link = p; - lastp = p; + (*last)->link = p; + *last = p; a = p->as; - if(a == AJMP || a == ARET || a == AIRETL || a == AIRETQ || a == AIRETW || - a == ARETFL || a == ARETFQ || a == ARETFW) + + /* continue loop with what comes after p */ + if(nofollow(a)) return; - if(p->pcond != P) - if(a != ACALL) { + if(p->pcond != P && a != ACALL) { + /* + * some kind of conditional branch. + * recurse to follow one path. + * continue loop on the other. + */ q = brchain(p->link); if(q != P && q->mark) if(a != ALOOP) { @@ -238,7 +199,7 @@ p->link = p->pcond; p->pcond = q; } - xfol(p->link); + xfol(p->link, last); q = brchain(p->pcond); if(q->mark) { p->pcond = q; @@ -251,6 +212,18 @@ goto loop; } +Prog* +byteq(int v) +{ + Prog *p; + + p = prg(); + p->as = ABYTE; + p->from.type = D_CONST; + p->from.offset = v&0xff; + return p; +} + int relinv(int a) { @@ -274,38 +247,17 @@ case AJOC: return AJOS; } diag("unknown relation: %s in %s", anames[a], TNAME); + errorexit(); return a; } void -doinit(void) -{ - Sym *s; - Prog *p; - int x; - - for(p = datap; p != P; p = p->link) { - x = p->to.type; - if(x != D_EXTERN && x != D_STATIC) - continue; - s = p->to.sym; - if(s->type == 0 || s->type == SXREF) - diag("undefined %s initializer of %s", - s->name, p->from.sym->name); - p->to.offset += s->value; - p->to.type = D_CONST; - if(s->type == SDATA || s->type == SBSS) - p->to.offset += INITDAT; - } -} - -void patch(void) { - long c; + int32 c; Prog *p, *q; Sym *s; - long vexit; + int32 vexit; if(debug['v']) Bprint(&bso, "%5.2f mkfwd\n", cputime()); @@ -314,58 +266,85 @@ if(debug['v']) Bprint(&bso, "%5.2f patch\n", cputime()); Bflush(&bso); + s = lookup("exit", 0); vexit = s->value; - for(p = firstp; p != P; p = p->link) { - if(p->as == ATEXT) - curtext = p; - if(p->as == ACALL || p->as == ARET) { + for(cursym = textp; cursym != nil; cursym = cursym->next) + for(p = cursym->text; p != P; p = p->link) { + if(HEADTYPE == Hwindows) { + // Windows + // Convert + // op n(GS), reg + // to + // MOVL 0x58(GS), reg + // op n(reg), reg + // The purpose of this patch is to fix some accesses + // to extern register variables (TLS) on Windows, as + // a different method is used to access them. + if(p->from.type == D_INDIR+D_GS + && p->to.type >= D_AX && p->to.type <= D_DI + && p->from.offset <= 8) { + q = appendp(p); + q->from = p->from; + q->from.type = D_INDIR + p->to.type; + q->to = p->to; + q->as = p->as; + p->as = AMOVQ; + p->from.type = D_INDIR+D_GS; + p->from.offset = 0x58; + } + } + if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd + || HEADTYPE == Hopenbsd) { + // ELF uses FS instead of GS. + if(p->from.type == D_INDIR+D_GS) + p->from.type = D_INDIR+D_FS; + if(p->to.type == D_INDIR+D_GS) + p->to.type = D_INDIR+D_FS; + } + if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH)) { s = p->to.sym; if(s) { if(debug['c']) Bprint(&bso, "%s calls %s\n", TNAME, s->name); - switch(s->type) { - default: - diag("undefined: %s in %s", s->name, TNAME); + if((s->type&~SSUB) != STEXT) { + /* diag prints TNAME first */ + diag("undefined: %s", s->name); s->type = STEXT; s->value = vexit; - break; /* or fall through to set offset? */ - case STEXT: - p->to.offset = s->value; - break; - case SUNDEF: - p->pcond = UP; - p->to.offset = 0; - break; + continue; // avoid more error messages } + if(s->text == nil) + continue; p->to.type = D_BRANCH; + p->to.offset = s->text->pc; + p->pcond = s->text; + continue; } } - if(p->to.type != D_BRANCH || p->pcond == UP) + if(p->to.type != D_BRANCH) continue; c = p->to.offset; - for(q = firstp; q != P;) { - if(q->forwd != P) - if(c >= q->forwd->pc) { - q = q->forwd; - continue; - } + for(q = cursym->text; q != P;) { if(c == q->pc) break; - q = q->link; + if(q->forwd != P && c >= q->forwd->pc) + q = q->forwd; + else + q = q->link; } if(q == P) { - diag("branch out of range in %s\n%P", TNAME, p); + diag("branch out of range in %s (%#ux)\n%P [%s]", + TNAME, c, p, p->to.sym ? p->to.sym->name : ""); p->to.type = D_NONE; } p->pcond = q; } - for(p = firstp; p != P; p = p->link) { - if(p->as == ATEXT) - curtext = p; + for(cursym = textp; cursym != nil; cursym = cursym->next) + for(p = cursym->text; p != P; p = p->link) { p->mark = 0; /* initialization for follow */ - if(p->pcond != P && p->pcond != UP) { + if(p->pcond != P) { p->pcond = brloop(p->pcond); if(p->pcond != P) if(p->to.type == D_BRANCH) @@ -374,40 +353,6 @@ } } -#define LOG 5 -void -mkfwd(void) -{ - Prog *p; - int i; - long dwn[LOG], cnt[LOG]; - 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) { @@ -425,170 +370,314 @@ return q; } +static char* +morename[] = +{ + "runtime.morestack00", + "runtime.morestack10", + "runtime.morestack01", + "runtime.morestack11", + + "runtime.morestack8", + "runtime.morestack16", + "runtime.morestack24", + "runtime.morestack32", + "runtime.morestack40", + "runtime.morestack48", +}; +Prog* pmorestack[nelem(morename)]; +Sym* symmorestack[nelem(morename)]; + void dostkoff(void) { - Prog *p, *q; - long autoffset, deltasp; - int a, f, curframe, curbecome, maxbecome, pcsize; + Prog *p, *q, *q1; + int32 autoffset, deltasp; + int a, pcsize; + uint32 moreconst1, moreconst2, i; - curframe = 0; - curbecome = 0; - maxbecome = 0; - curtext = 0; - for(p = firstp; p != P; p = p->link) { - - /* find out how much arg space is used in this TEXT */ - if(p->to.type == (D_INDIR+D_SP)) - if(p->to.offset > curframe) - curframe = p->to.offset; - - switch(p->as) { - case ATEXT: - if(curtext && curtext->from.sym) { - curtext->from.sym->frame = curframe; - curtext->from.sym->become = curbecome; - if(curbecome > maxbecome) - maxbecome = curbecome; - } - curframe = 0; - curbecome = 0; - - curtext = p; - break; - - case ARET: - /* special form of RET is BECOME */ - if(p->from.type == D_CONST) - if(p->from.offset > curbecome) - curbecome = p->from.offset; - break; - } - } - if(curtext && curtext->from.sym) { - curtext->from.sym->frame = curframe; - curtext->from.sym->become = curbecome; - if(curbecome > maxbecome) - maxbecome = curbecome; + for(i=0; itype != STEXT) + diag("morestack trampoline not defined - %s", morename[i]); + pmorestack[i] = symmorestack[i]->text; } - if(debug['b']) - print("max become = %d\n", maxbecome); - xdefine("ALEFbecome", STEXT, maxbecome); + for(cursym = textp; cursym != nil; cursym = cursym->next) { + if(cursym->text == nil || cursym->text->link == nil) + continue; - curtext = 0; - for(p = firstp; p != P; p = p->link) { - switch(p->as) { - case ATEXT: - curtext = p; - break; - case ACALL: - if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) { - f = maxbecome - curtext->from.sym->frame; - if(f <= 0) - break; - /* calling a become or calling a variable */ - if(p->to.sym == S || p->to.sym->become) { - curtext->to.offset += f; - if(debug['b']) { - curp = p; - print("%D calling %D increase %d\n", - &curtext->from, &p->to, f); - } + p = cursym->text; + parsetextconst(p->to.offset); + autoffset = textstksiz; + if(autoffset < 0) + autoffset = 0; + + q = P; + if((p->from.scale & NOSPLIT) && autoffset >= StackSmall) + diag("nosplit func likely to overflow stack"); + + if(!(p->from.scale & NOSPLIT)) { + p = appendp(p); // load g into CX + p->as = AMOVQ; + if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd + || HEADTYPE == Hopenbsd) // ELF uses FS + p->from.type = D_INDIR+D_FS; + else + p->from.type = D_INDIR+D_GS; + p->from.offset = tlsoffset+0; + p->to.type = D_CX; + if(HEADTYPE == Hwindows) { + // movq %gs:0x58, %rcx + // movq (%rcx), %rcx + p->as = AMOVQ; + p->from.type = D_INDIR+D_GS; + p->from.offset = 0x58; + p->to.type = D_CX; + + + p = appendp(p); + p->as = AMOVQ; + p->from.type = D_INDIR+D_CX; + p->from.offset = 0; + p->to.type = D_CX; + } + + if(debug['K']) { + // 6l -K means check not only for stack + // overflow but stack underflow. + // On underflow, INT 3 (breakpoint). + // Underflow itself is rare but this also + // catches out-of-sync stack guard info + + p = appendp(p); + p->as = ACMPQ; + p->from.type = D_INDIR+D_CX; + p->from.offset = 8; + p->to.type = D_SP; + + p = appendp(p); + p->as = AJHI; + p->to.type = D_BRANCH; + p->to.offset = 4; + q1 = p; + + p = appendp(p); + p->as = AINT; + p->from.type = D_CONST; + p->from.offset = 3; + + p = appendp(p); + p->as = ANOP; + q1->pcond = p; + } + + if(autoffset < StackBig) { // do we need to call morestack? + if(autoffset <= StackSmall) { + // small stack + p = appendp(p); + p->as = ACMPQ; + p->from.type = D_SP; + p->to.type = D_INDIR+D_CX; + } else { + // large stack + p = appendp(p); + p->as = ALEAQ; + p->from.type = D_INDIR+D_SP; + p->from.offset = -(autoffset-StackSmall); + p->to.type = D_AX; + + p = appendp(p); + p->as = ACMPQ; + p->from.type = D_AX; + p->to.type = D_INDIR+D_CX; } + + // common + p = appendp(p); + p->as = AJHI; + p->to.type = D_BRANCH; + p->to.offset = 4; + q = p; } - break; + + /* 160 comes from 3 calls (3*8) 4 safes (4*8) and 104 guard */ + moreconst1 = 0; + if(autoffset+160+textarg > 4096) + moreconst1 = (autoffset+160) & ~7LL; + moreconst2 = textarg; + + // 4 varieties varieties (const1==0 cross const2==0) + // and 6 subvarieties of (const1==0 and const2!=0) + p = appendp(p); + if(moreconst1 == 0 && moreconst2 == 0) { + p->as = ACALL; + p->to.type = D_BRANCH; + p->pcond = pmorestack[0]; + p->to.sym = symmorestack[0]; + } else + if(moreconst1 != 0 && moreconst2 == 0) { + p->as = AMOVL; + p->from.type = D_CONST; + p->from.offset = moreconst1; + p->to.type = D_AX; + + p = appendp(p); + p->as = ACALL; + p->to.type = D_BRANCH; + p->pcond = pmorestack[1]; + p->to.sym = symmorestack[1]; + } else + if(moreconst1 == 0 && moreconst2 <= 48 && moreconst2%8 == 0) { + i = moreconst2/8 + 3; + p->as = ACALL; + p->to.type = D_BRANCH; + p->pcond = pmorestack[i]; + p->to.sym = symmorestack[i]; + } else + if(moreconst1 == 0 && moreconst2 != 0) { + p->as = AMOVL; + p->from.type = D_CONST; + p->from.offset = moreconst2; + p->to.type = D_AX; + + p = appendp(p); + p->as = ACALL; + p->to.type = D_BRANCH; + p->pcond = pmorestack[2]; + p->to.sym = symmorestack[2]; + } else { + p->as = AMOVQ; + p->from.type = D_CONST; + p->from.offset = (uint64)moreconst2 << 32; + p->from.offset |= moreconst1; + p->to.type = D_AX; + + p = appendp(p); + p->as = ACALL; + p->to.type = D_BRANCH; + p->pcond = pmorestack[3]; + p->to.sym = symmorestack[3]; + } } - } - autoffset = 0; - deltasp = 0; - for(p = firstp; p != P; p = p->link) { - if(p->as == ATEXT) { - curtext = p; - autoffset = p->to.offset; - if(autoffset < 0) - autoffset = 0; + if(q != P) + q->pcond = p->link; + + if(autoffset) { + p = appendp(p); + p->as = AADJSP; + p->from.type = D_CONST; + p->from.offset = autoffset; + p->spadj = autoffset; + if(q != P) + q->pcond = p; + } + deltasp = autoffset; + + if(debug['K'] > 1 && autoffset) { + // 6l -KK means double-check for stack overflow + // even after calling morestack and even if the + // function is marked as nosplit. + p = appendp(p); + p->as = AMOVQ; + p->from.type = D_INDIR+D_CX; + p->from.offset = 0; + p->to.type = D_BX; + + p = appendp(p); + p->as = ASUBQ; + p->from.type = D_CONST; + p->from.offset = StackSmall+32; + p->to.type = D_BX; + + p = appendp(p); + p->as = ACMPQ; + p->from.type = D_SP; + p->to.type = D_BX; + + p = appendp(p); + p->as = AJHI; + p->to.type = D_BRANCH; + q1 = p; + + p = appendp(p); + p->as = AINT; + p->from.type = D_CONST; + p->from.offset = 3; + + p = appendp(p); + p->as = ANOP; + q1->pcond = p; + } + + for(; p != P; p = p->link) { + pcsize = p->mode/8; + a = p->from.type; + if(a == D_AUTO) + p->from.offset += deltasp; + if(a == D_PARAM) + p->from.offset += deltasp + pcsize; + a = p->to.type; + if(a == D_AUTO) + p->to.offset += deltasp; + if(a == D_PARAM) + p->to.offset += deltasp + pcsize; + + switch(p->as) { + default: + continue; + case APUSHL: + case APUSHFL: + deltasp += 4; + p->spadj = 4; + continue; + case APUSHQ: + case APUSHFQ: + deltasp += 8; + p->spadj = 8; + continue; + case APUSHW: + case APUSHFW: + deltasp += 2; + p->spadj = 2; + continue; + case APOPL: + case APOPFL: + deltasp -= 4; + p->spadj = -4; + continue; + case APOPQ: + case APOPFQ: + deltasp -= 8; + p->spadj = -8; + continue; + case APOPW: + case APOPFW: + deltasp -= 2; + p->spadj = -2; + continue; + case ARET: + break; + } + + if(autoffset != deltasp) + diag("unbalanced PUSH/POP"); + if(autoffset) { - p = appendp(p); p->as = AADJSP; p->from.type = D_CONST; - p->from.offset = autoffset; + p->from.offset = -autoffset; + p->spadj = -autoffset; + p = appendp(p); + p->as = ARET; + // If there are instructions following + // this ARET, they come from a branch + // with the same stackframe, so undo + // the cleanup. + p->spadj = +autoffset; } - deltasp = autoffset; } - pcsize = p->mode/8; - a = p->from.type; - if(a == D_AUTO) - p->from.offset += deltasp; - if(a == D_PARAM) - p->from.offset += deltasp + pcsize; - a = p->to.type; - if(a == D_AUTO) - p->to.offset += deltasp; - if(a == D_PARAM) - p->to.offset += deltasp + pcsize; - - switch(p->as) { - default: - continue; - case APUSHL: - case APUSHFL: - deltasp += 4; - continue; - case APUSHQ: - case APUSHFQ: - deltasp += 8; - continue; - case APUSHW: - case APUSHFW: - deltasp += 2; - continue; - case APOPL: - case APOPFL: - deltasp -= 4; - continue; - case APOPQ: - case APOPFQ: - deltasp -= 8; - continue; - case APOPW: - case APOPFW: - deltasp -= 2; - continue; - case ARET: - break; - } - - if(autoffset != deltasp) - diag("unbalanced PUSH/POP"); - if(p->from.type == D_CONST) - goto become; - - if(autoffset) { - q = p; - p = appendp(p); - p->as = ARET; - - q->as = AADJSP; - q->from.type = D_CONST; - q->from.offset = -autoffset; - } - continue; - - become: - q = p; - p = appendp(p); - p->as = AJMP; - p->to = q->to; - p->pcond = q->pcond; - - q->as = AADJSP; - q->from = zprg.from; - q->from.type = D_CONST; - q->from.offset = -autoffset; - q->to = zprg.to; - continue; } } @@ -631,160 +720,3 @@ n = -n; return n; } - -void -undef(void) -{ - int i; - Sym *s; - - for(i=0; ilink) - if(s->type == SXREF) - diag("%s: not defined", s->name); -} - -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)){ - if(s->value != 0) - diag("value != 0 on SXREF"); - undefsym(s); - Bprint(&bso, "IMPORT: %s sig=%lux v=%lld\n", s->name, s->sig, s->value); - if(debug['S']) - s->sig = 0; - } -} - -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(); - if(edatap == P) - datap = p; - else - edatap->link = p; - edatap = p; - p->as = ADATA; - p->width = w; - p->from.scale = w; - p->from.type = t; - p->from.sym = s; - p->from.offset = o; - p->to.type = D_CONST; - 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]; - if(debug['S']) - s->sig = 0; - /* 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.type = D_ADDR; - p->to.index = 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; - memmove(p->to.scon, buf, NSNAME); - nb = 0; - } - if(*t++ == 0) - break; - } - - /* name */ - p = newdata(et, off, sizeof(long), D_EXTERN); - off += sizeof(long); - p->to.type = D_ADDR; - p->to.index = 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; - memmove(p->to.scon, 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); -} diff -r d8d00747375b sys/src/cmd/6l/prof.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/src/cmd/6l/prof.c Mon Nov 14 17:35:25 2011 +0100 @@ -0,0 +1,171 @@ +// Inferno utils/6l/obj.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.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. + +// Profiling. + +#include "l.h" +#include "../ld/lib.h" + +void +doprof1(void) +{ +#ifdef NOTDEF + Sym *s; + int32 n; + Prog *p, *q; + + if(debug['v']) + Bprint(&bso, "%5.2f profile 1\n", cputime()); + Bflush(&bso); + s = lookup("__mcount", 0); + n = 1; + for(cursym = textp; cursym != nil; cursym = cursym->next) { + p = cursym->text; + q = prg(); + q->line = p->line; + q->link = datap; + datap = q; + q->as = ADATA; + q->from.type = D_EXTERN; + q->from.offset = n*4; + q->from.sym = s; + q->from.scale = 4; + q->to = p->from; + q->to.type = D_CONST; + + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + p->as = AADDL; + p->from.type = D_CONST; + p->from.offset = 1; + p->to.type = D_EXTERN; + p->to.sym = s; + p->to.offset = n*4 + 4; + + n += 2; + } + q = prg(); + q->line = 0; + q->link = datap; + datap = q; + + q->as = ADATA; + q->from.type = D_EXTERN; + q->from.sym = s; + q->from.scale = 4; + q->to.type = D_CONST; + q->to.offset = n; + + s->type = SBSS; + s->size = n*4; +#endif +} + +void +doprof2(void) +{ + Sym *s2, *s4; + Prog *p, *q, *ps2, *ps4; + + if(debug['v']) + Bprint(&bso, "%5.2f profile 2\n", cputime()); + Bflush(&bso); + + s2 = lookup("_profin", 0); + s4 = lookup("_profout", 0); + if(s2->type != STEXT || s4->type != STEXT) { + diag("_profin/_profout not defined"); + return; + } + + ps2 = P; + ps4 = P; + for(cursym = textp; cursym != nil; cursym = cursym->next) { + p = cursym->text; + if(p->from.sym == s2) { + p->from.scale = 1; + ps2 = p; + } + if(p->from.sym == s4) { + p->from.scale = 1; + ps4 = p; + } + } + for(cursym = textp; cursym != nil; cursym = cursym->next) { + p = cursym->text; + + if(p->from.scale & NOPROF) /* dont profile */ + continue; + + /* + * JMPL profin + */ + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + p->as = ACALL; + p->to.type = D_BRANCH; + p->pcond = ps2; + p->to.sym = s2; + + for(; p; p=p->link) { + if(p->as == ARET) { + /* + * RET + */ + q = prg(); + q->as = ARET; + q->from = p->from; + q->to = p->to; + q->link = p->link; + p->link = q; + + /* + * JAL profout + */ + p->as = ACALL; + p->from = zprg.from; + p->to = zprg.to; + p->to.type = D_BRANCH; + p->pcond = ps4; + p->to.sym = s4; + + p = q; + } + } + } +} diff -r d8d00747375b sys/src/cmd/6l/span.c --- a/sys/src/cmd/6l/span.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/6l/span.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,29 +1,60 @@ +// Inferno utils/6l/span.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.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. + +// Instruction layout. + #include "l.h" +#include "../ld/lib.h" static int rexflag; static int asmode; +static vlong vaddr(Adr*, Reloc*); void -span(void) +span1(Sym *s) { Prog *p, *q; - long v; - vlong c, idat; - int m, n, again; + int32 c, v, loop; + uchar *bp; + int n, m, i; - xdefine("etext", STEXT, 0L); - idat = INITDAT; - for(p = firstp; p != P; p = p->link) { - if(p->as == ATEXT) - curtext = p; - n = 0; - if(p->to.type == D_BRANCH) - if(p->pcond == P) - p->pcond = p; - if((q = p->pcond) != P) - if(q->back != 2) - n = 1; - p->back = n; + cursym = s; + + if(s->p != nil) + return; + + for(p = s->text; p != P; p = p->link) { + p->back = 2; // use short branches first time through + if((q = p->pcond) != P && (q->back & 2)) + p->back |= 1; // backward jump + if(p->as == AADJSP) { p->to.type = D_SP; v = -p->from.offset; @@ -38,71 +69,114 @@ p->as = ANOP; } } + n = 0; + do { + loop = 0; + memset(s->r, 0, s->nr*sizeof s->r[0]); + s->nr = 0; + s->np = 0; + c = 0; + for(p = s->text; p != P; p = p->link) { + p->pc = c; -start: + // process forward jumps to p + for(q = p->comefrom; q != P; q = q->forwd) { + v = p->pc - (q->pc + q->mark); + if(q->back & 2) { // short + if(v > 127) { + loop++; + q->back ^= 2; + } + if(q->as == AJCXZL) + s->p[q->pc+2] = v; + else + s->p[q->pc+1] = v; + } else { + bp = s->p + q->pc + q->mark - 4; + *bp++ = v; + *bp++ = v>>8; + *bp++ = v>>16; + *bp = v>>24; + } + } + p->comefrom = P; + + asmins(p); + p->pc = c; + m = andptr-and; + symgrow(s, p->pc+m); + memmove(s->p+p->pc, and, m); + p->mark = m; + c += m; + } + if(++n > 20) { + diag("span must be looping"); + errorexit(); + } + } while(loop); + s->size = c; + + if(debug['a'] > 1) { + print("span1 %s %lld (%d tries)\n %.6ux", s->name, s->size, n, 0); + for(i=0; inp; i++) { + print(" %.2ux", s->p[i]); + if(i%16 == 15) + print("\n %.6ux", i+1); + } + if(i%16) + print("\n"); + + for(i=0; inr; i++) { + Reloc *r; + + r = &s->r[i]; + print(" rel %#.4ux/%d %s%+lld\n", r->off, r->siz, r->sym->name, r->add); + } + } +} + +void +span(void) +{ + Prog *p, *q; + int32 v; + int n; + if(debug['v']) Bprint(&bso, "%5.2f span\n", cputime()); - Bflush(&bso); - c = INITTEXT; - for(p = firstp; p != P; p = p->link) { - if(p->as == ATEXT) - curtext = p; - if(p->to.type == D_BRANCH) - if(p->back) - p->pc = c; - asmins(p); - p->pc = c; - m = andptr-and; - p->mark = m; - c += m; - } -loop: - n++; - if(debug['v']) - Bprint(&bso, "%5.2f span %d\n", cputime(), n); - Bflush(&bso); - if(n > 50) { - print("span must be looping\n"); - errorexit(); - } - again = 0; - c = INITTEXT; - for(p = firstp; p != P; p = p->link) { - if(p->as == ATEXT) - curtext = p; - if(p->to.type == D_BRANCH || p->back & 0100) { - if(p->back) - p->pc = c; - asmins(p); - m = andptr-and; - if(m != p->mark) { - p->mark = m; - again++; + // NOTE(rsc): If we get rid of the globals we should + // be able to parallelize these iterations. + for(cursym = textp; cursym != nil; cursym = cursym->next) { + if(cursym->p != nil) + continue; + // TODO: move into span1 + for(p = cursym->text; p != P; p = p->link) { + n = 0; + if(p->to.type == D_BRANCH) + if(p->pcond == P) + p->pcond = p; + if((q = p->pcond) != P) + if(q->back != 2) + n = 1; + p->back = n; + if(p->as == AADJSP) { + p->to.type = D_SP; + v = -p->from.offset; + p->from.offset = v; + p->as = p->mode != 64? AADDL: AADDQ; + if(v < 0) { + p->as = p->mode != 64? ASUBL: ASUBQ; + v = -v; + p->from.offset = v; + } + if(v == 0) + p->as = ANOP; } } - p->pc = c; - c += p->mark; + span1(cursym); } - if(again) { - textsize = c; - goto loop; - } - if(INITRND) { - INITDAT = rnd(c, INITRND); - if(INITDAT != idat) { - idat = INITDAT; - goto start; - } - } - xdefine("etext", STEXT, c); - if(debug['v']) - Bprint(&bso, "etext = %llux\n", c); - Bflush(&bso); - for(p = textp; p != P; p = p->pcond) - p->from.sym->value = p->pc; - textsize = c - INITTEXT; } void @@ -111,212 +185,143 @@ Sym *s; s = lookup(p, 0); - if(s->type == 0 || s->type == SXREF) { - s->type = t; - s->value = v; - } - if(s->type == STEXT && s->value == 0) - s->value = v; + s->type = t; + s->value = v; + s->reachable = 1; + s->special = 1; } void -putsymb(char *s, int t, vlong v, int ver) +instinit(void) { - int i, f, l; + int c, i; - if(t == 'f') - s++; - l = 4; - if(!debug['8']){ - lput(v>>32); - l = 8; + for(i=1; optab[i].as; i++) { + c = optab[i].as; + if(opindex[c] != nil) { + diag("phase error in optab: %d (%A)", i, c); + errorexit(); + } + opindex[c] = &optab[i]; } - lput(v); - if(ver) - t += 'a' - 'A'; - cput(t+0x80); /* 0x80 is variable length */ - if(t == 'Z' || t == 'z') { - cput(s[0]); - for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) { - cput(s[i]); - cput(s[i+1]); + for(i=0; i= D_AL && i <= D_R15B) { + reg[i] = (i-D_AL) & 7; + if(i >= D_SPB && i <= D_DIB) + regrex[i] = 0x40; + if(i >= D_R8B && i <= D_R15B) + regrex[i] = Rxr | Rxx | Rxb; } - cput(0); - cput(0); - i++; - } - else { - for(i=0; s[i]; i++) - cput(s[i]); - cput(0); - } - symsize += l + 1 + i + 1; - - if(debug['n']) { - if(t == 'z' || t == 'Z') { - Bprint(&bso, "%c %.8llux ", t, v); - for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) { - f = ((s[i]&0xff) << 8) | (s[i+1]&0xff); - Bprint(&bso, "/%x", f); - } - Bprint(&bso, "\n"); - return; + if(i >= D_AH && i<= D_BH) + reg[i] = 4 + ((i-D_AH) & 7); + if(i >= D_AX && i <= D_R15) { + reg[i] = (i-D_AX) & 7; + if(i >= D_R8) + regrex[i] = Rxr | Rxx | Rxb; } - if(ver) - Bprint(&bso, "%c %.8llux %s<%d>\n", t, v, s, ver); - else - Bprint(&bso, "%c %.8llux %s\n", t, v, s); + if(i >= D_F0 && i <= D_F0+7) + reg[i] = (i-D_F0) & 7; + if(i >= D_M0 && i <= D_M0+7) + reg[i] = (i-D_M0) & 7; + if(i >= D_X0 && i <= D_X0+15) { + reg[i] = (i-D_X0) & 7; + if(i >= D_X0+8) + regrex[i] = Rxr | Rxx | Rxb; + } + if(i >= D_CR+8 && i <= D_CR+15) + regrex[i] = Rxr; } } -void -asmsym(void) +int +prefixof(Adr *a) { - Prog *p; - Auto *a; - Sym *s; - int h; - - s = lookup("etext", 0); - if(s->type == STEXT) - putsymb(s->name, 'T', s->value, s->version); - - for(h=0; hlink) - switch(s->type) { - case SCONST: - putsymb(s->name, 'D', s->value, s->version); - continue; - - case SDATA: - putsymb(s->name, 'D', s->value+INITDAT, s->version); - continue; - - case SBSS: - putsymb(s->name, 'B', s->value+INITDAT, s->version); - continue; - - case SFILE: - putsymb(s->name, 'f', s->value, s->version); - continue; - } - - for(p=textp; p!=P; p=p->pcond) { - s = p->from.sym; - if(s->type != STEXT) - continue; - - /* filenames first */ - for(a=p->to.autom; a; a=a->link) - if(a->type == D_FILE) - putsymb(a->asym->name, 'z', a->aoffset, 0); - else - if(a->type == D_FILE1) - putsymb(a->asym->name, 'Z', a->aoffset, 0); - - putsymb(s->name, 'T', s->value, s->version); - - /* frame, auto and param after */ - putsymb(".frame", 'm', p->to.offset+8, 0); - - for(a=p->to.autom; a; a=a->link) - if(a->type == D_AUTO) - putsymb(a->asym->name, 'a', -a->aoffset, 0); - else - if(a->type == D_PARAM) - putsymb(a->asym->name, 'p', a->aoffset, 0); + switch(a->type) { + case D_INDIR+D_CS: + return 0x2e; + case D_INDIR+D_DS: + return 0x3e; + case D_INDIR+D_ES: + return 0x26; + case D_INDIR+D_FS: + return 0x64; + case D_INDIR+D_GS: + return 0x65; } - if(debug['v'] || debug['n']) - Bprint(&bso, "symsize = %lud\n", symsize); - Bflush(&bso); -} - -void -asmlc(void) -{ - vlong oldpc; - Prog *p; - long oldlc, v, s; - - oldpc = INITTEXT; - oldlc = 0; - for(p = firstp; p != P; p = p->link) { - if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) { - if(p->as == ATEXT) - curtext = p; - if(debug['L']) - Bprint(&bso, "%6llux %P\n", - p->pc, p); - continue; - } - if(debug['L']) - Bprint(&bso, "\t\t%6ld", lcsize); - v = (p->pc - oldpc) / MINLC; - while(v) { - s = 127; - if(v < 127) - s = v; - cput(s+128); /* 129-255 +pc */ - if(debug['L']) - Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128); - v -= s; - lcsize++; - } - s = p->line - oldlc; - oldlc = p->line; - oldpc = p->pc + MINLC; - if(s > 64 || s < -64) { - cput(0); /* 0 vv +lc */ - cput(s>>24); - cput(s>>16); - cput(s>>8); - cput(s); - if(debug['L']) { - if(s > 0) - Bprint(&bso, " lc+%ld(%d,%ld)\n", - s, 0, s); - else - Bprint(&bso, " lc%ld(%d,%ld)\n", - s, 0, s); - Bprint(&bso, "%6llux %P\n", - p->pc, p); - } - lcsize += 5; - continue; - } - if(s > 0) { - cput(0+s); /* 1-64 +lc */ - if(debug['L']) { - Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s); - Bprint(&bso, "%6llux %P\n", - p->pc, p); - } - } else { - cput(64-s); /* 65-128 -lc */ - if(debug['L']) { - Bprint(&bso, " lc%ld(%ld)\n", s, 64-s); - Bprint(&bso, "%6llux %P\n", - p->pc, p); - } - } - lcsize++; - } - while(lcsize & 1) { - s = 129; - cput(s); - lcsize++; - } - if(debug['v'] || debug['L']) - Bprint(&bso, "lcsize = %ld\n", lcsize); - Bflush(&bso); + return 0; } int oclass(Adr *a) { vlong v; - long l; + int32 l; if(a->type >= D_INDIR || a->index != D_NONE) { if(a->index != D_NONE && a->scale == 0) { @@ -509,11 +514,11 @@ } void -asmidx(Adr *a, int base) +asmidx(int scale, int index, int base) { int i; - switch(a->index) { + switch(index) { default: goto bad; @@ -538,10 +543,10 @@ case D_BP: case D_SI: case D_DI: - i = reg[a->index] << 3; + i = reg[index] << 3; break; } - switch(a->scale) { + switch(scale) { default: goto bad; case 1: @@ -587,18 +592,14 @@ *andptr++ = i; return; bad: - diag("asmidx: bad address %D", a); + diag("asmidx: bad address %d/%d/%d", scale, index, base); *andptr++ = 0; return; } static void -put4(long v) +put4(int32 v) { - if(dlm && curp != P && reloca != nil){ - dynreloc(reloca->sym, curp->pc + andptr - &and[0], 1); - reloca = nil; - } andptr[0] = v; andptr[1] = v>>8; andptr[2] = v>>16; @@ -607,12 +608,25 @@ } static void +relput4(Prog *p, Adr *a) +{ + vlong v; + Reloc rel, *r; + + v = vaddr(a, &rel); + if(rel.siz != 0) { + if(rel.siz != 4) + diag("bad reloc"); + r = addrel(cursym); + *r = rel; + r->off = p->pc + andptr - and; + } + put4(v); +} + +static void put8(vlong v) { - if(dlm && curp != P && reloca != nil){ - dynreloc(reloca->sym, curp->pc + andptr - &and[0], 1); /* TO DO */ - reloca = nil; - } andptr[0] = v; andptr[1] = v>>8; andptr[2] = v>>16; @@ -624,12 +638,41 @@ andptr += 8; } +/* +static void +relput8(Prog *p, Adr *a) +{ + vlong v; + Reloc rel, *r; + + v = vaddr(a, &rel); + if(rel.siz != 0) { + r = addrel(cursym); + *r = rel; + r->siz = 8; + r->off = p->pc + andptr - and; + } + put8(v); +} +*/ + vlong -vaddr(Adr *a) +symaddr(Sym *s) +{ + if(!s->reachable) + diag("unreachable symbol in symaddr - %s", s->name); + return s->value; +} + +static vlong +vaddr(Adr *a, Reloc *r) { int t; vlong v; Sym *s; + + if(r != nil) + memset(r, 0, sizeof *r); t = a->type; v = a->offset; @@ -639,22 +682,18 @@ case D_STATIC: case D_EXTERN: s = a->sym; - if(s != nil) { - if(dlm && curp != P) - reloca = a; - switch(s->type) { - case SUNDEF: - ckoff(s, v); - case STEXT: - case SCONST: - if((uvlong)s->value < (uvlong)INITTEXT) - v += INITTEXT; /* TO DO */ - v += s->value; - break; - default: - v += INITDAT + s->value; - } + if(!s->reachable) + diag("unreachable symbol in vaddr - %s", s->name); + if(r == nil) { + diag("need reloc for %D", a); + errorexit(); } + r->type = D_ADDR; + r->siz = 4; // TODO: 8 for external symbols + r->off = -1; // caller must fill in + r->sym = s; + r->add = v; + v = 0; } return v; } @@ -662,56 +701,52 @@ static void asmandsz(Adr *a, int r, int rex, int m64) { - long v; - int t; - Adr aa; + int32 v; + int t, scale; + Reloc rel; + USED(m64); rex &= (0x40 | Rxr); v = a->offset; t = a->type; + rel.siz = 0; if(a->index != D_NONE) { - if(t >= D_INDIR) { + if(t < D_INDIR) { + switch(t) { + default: + goto bad; + case D_STATIC: + case D_EXTERN: + t = D_NONE; + v = vaddr(a, &rel); + break; + case D_AUTO: + case D_PARAM: + t = D_SP; + break; + } + } else t -= D_INDIR; - rexflag |= (regrex[a->index] & Rxx) | (regrex[t] & Rxb) | rex; - if(t == D_NONE) { - *andptr++ = (0 << 6) | (4 << 0) | (r << 3); - asmidx(a, t); - put4(v); - return; - } - if(v == 0 && t != D_BP && t != D_R13) { - *andptr++ = (0 << 6) | (4 << 0) | (r << 3); - asmidx(a, t); - return; - } - if(v >= -128 && v < 128) { - *andptr++ = (1 << 6) | (4 << 0) | (r << 3); - asmidx(a, t); - *andptr++ = v; - return; - } - *andptr++ = (2 << 6) | (4 << 0) | (r << 3); - asmidx(a, t); - put4(v); + rexflag |= (regrex[(int)a->index] & Rxx) | (regrex[t] & Rxb) | rex; + if(t == D_NONE) { + *andptr++ = (0 << 6) | (4 << 0) | (r << 3); + asmidx(a->scale, a->index, t); + goto putrelv; + } + if(v == 0 && rel.siz == 0 && t != D_BP && t != D_R13) { + *andptr++ = (0 << 6) | (4 << 0) | (r << 3); + asmidx(a->scale, a->index, t); return; } - switch(t) { - default: - goto bad; - case D_STATIC: - case D_EXTERN: - aa.type = D_NONE+D_INDIR; - break; - case D_AUTO: - case D_PARAM: - aa.type = D_SP+D_INDIR; - break; + if(v >= -128 && v < 128 && rel.siz == 0) { + *andptr++ = (1 << 6) | (4 << 0) | (r << 3); + asmidx(a->scale, a->index, t); + *andptr++ = v; + return; } - aa.offset = vaddr(a); - aa.index = a->index; - aa.scale = a->scale; - asmandsz(&aa, r, rex, m64); - return; + *andptr++ = (2 << 6) | (4 << 0) | (r << 3); + asmidx(a->scale, a->index, t); + goto putrelv; } if(t >= D_AL && t <= D_X0+15) { if(v) @@ -720,72 +755,84 @@ rexflag |= (regrex[t] & (0x40 | Rxb)) | rex; return; } - if(t >= D_INDIR) { + + scale = a->scale; + if(t < D_INDIR) { + switch(a->type) { + default: + goto bad; + case D_STATIC: + case D_EXTERN: + t = D_NONE; + v = vaddr(a, &rel); + break; + case D_AUTO: + case D_PARAM: + t = D_SP; + break; + } + scale = 1; + } else t -= D_INDIR; - rexflag |= (regrex[t] & Rxb) | rex; - if(t == D_NONE) { - if(asmode != 64){ - *andptr++ = (0 << 6) | (5 << 0) | (r << 3); - put4(v); - return; - } - /* temporary */ - *andptr++ = (0 << 6) | (4 << 0) | (r << 3); /* sib present */ - *andptr++ = (0 << 6) | (4 << 3) | (5 << 0); /* DS:d32 */ - put4(v); + + rexflag |= (regrex[t] & Rxb) | rex; + if(t == D_NONE || (D_CS <= t && t <= D_GS)) { + if(asmode != 64){ + *andptr++ = (0 << 6) | (5 << 0) | (r << 3); + goto putrelv; + } + /* temporary */ + *andptr++ = (0 << 6) | (4 << 0) | (r << 3); /* sib present */ + *andptr++ = (0 << 6) | (4 << 3) | (5 << 0); /* DS:d32 */ + goto putrelv; + } + if(t == D_SP || t == D_R12) { + if(v == 0) { + *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3); + asmidx(scale, D_NONE, t); return; } - if(t == D_SP || t == D_R12) { - if(v == 0) { - *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3); - asmidx(a, t); - return; - } - if(v >= -128 && v < 128) { - *andptr++ = (1 << 6) | (reg[t] << 0) | (r << 3); - asmidx(a, t); - *andptr++ = v; - return; - } - *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3); - asmidx(a, t); - put4(v); + if(v >= -128 && v < 128) { + *andptr++ = (1 << 6) | (reg[t] << 0) | (r << 3); + asmidx(scale, D_NONE, t); + *andptr++ = v; return; } - if(t >= D_AX && t <= D_R15) { - if(v == 0 && t != D_BP && t != D_R13) { - *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3); - return; - } - if(v >= -128 && v < 128) { - andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3); - andptr[1] = v; - andptr += 2; - return; - } - *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3); - put4(v); + *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3); + asmidx(scale, D_NONE, t); + goto putrelv; + } + if(t >= D_AX && t <= D_R15) { + if(v == 0 && t != D_BP && t != D_R13) { + *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3); return; } - goto bad; + if(v >= -128 && v < 128) { + andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3); + andptr[1] = v; + andptr += 2; + return; + } + *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3); + goto putrelv; } - switch(a->type) { - default: - goto bad; - case D_STATIC: - case D_EXTERN: - aa.type = D_NONE+D_INDIR; - break; - case D_AUTO: - case D_PARAM: - aa.type = D_SP+D_INDIR; - break; + goto bad; + +putrelv: + if(rel.siz != 0) { + Reloc *r; + + if(rel.siz != 4) { + diag("bad rel"); + goto bad; + } + r = addrel(cursym); + *r = rel; + r->off = curp->pc + andptr - and; } - aa.index = D_NONE; - aa.scale = 1; - aa.offset = vaddr(a); - asmandsz(&aa, r, rex, m64); + put4(v); return; + bad: diag("asmand: bad address %D", a); return; @@ -804,10 +851,12 @@ } static void -bytereg(Adr *a) +bytereg(Adr *a, char *t) { - if(a->index == D_NONE && (a->type >= D_AX && a->type <= D_R15)) + if(a->index == D_NONE && (a->type >= D_AX && a->type <= D_R15)) { a->type = D_AL + (a->type-D_AX); + *t = 0; + } } #define E 0xff @@ -1015,16 +1064,34 @@ Prog *q, pp; uchar *t; Movtab *mo; - int z, op, ft, tt, xo, l; + int z, op, ft, tt, xo, l, pre; vlong v; + Reloc rel, *r; + Adr *a; + + curp = p; // TODO o = opindex[p->as]; if(o == nil) { diag("asmins: missing op %P", p); return; } - ft = oclass(&p->from) * Ymax; - tt = oclass(&p->to) * Ymax; + + pre = prefixof(&p->from); + if(pre) + *andptr++ = pre; + pre = prefixof(&p->to); + if(pre) + *andptr++ = pre; + + if(p->ft == 0) + p->ft = oclass(&p->from); + if(p->tt == 0) + p->tt = oclass(&p->to); + + ft = p->ft * Ymax; + tt = p->tt * Ymax; + t = o->ytab; if(t == 0) { diag("asmins: noproto %P", p); @@ -1065,8 +1132,8 @@ break; case Pb: /* botch */ - bytereg(&p->from); - bytereg(&p->to); + bytereg(&p->from, &p->ft); + bytereg(&p->to, &p->tt); break; case P32: /* 32 bit but illegal if 64-bit mode */ @@ -1079,7 +1146,7 @@ diag("asmins: illegal in %d-bit mode: %P", p->mode, p); break; } - v = vaddr(&p->from); + op = o->op[z]; if(op == 0x0f) { *andptr++ = op; @@ -1098,8 +1165,14 @@ *andptr++ = op; break; + case Zlitm_r: + for(; op = o->op[z]; z++) + *andptr++ = op; + asmand(&p->from, &p->to); + break; + case Zmb_r: - bytereg(&p->from); + bytereg(&p->from, &p->ft); /* fall through */ case Zm_r: *andptr++ = op; @@ -1185,64 +1258,74 @@ break; case Zm_ibo: - v = vaddr(&p->to); *andptr++ = op; asmando(&p->from, o->op[z+1]); - *andptr++ = v; + *andptr++ = vaddr(&p->to, nil); break; case Zibo_m: *andptr++ = op; asmando(&p->to, o->op[z+1]); - *andptr++ = v; + *andptr++ = vaddr(&p->from, nil); break; case Zibo_m_xm: z = mediaop(o, op, t[3], z); asmando(&p->to, o->op[z+1]); - *andptr++ = v; + *andptr++ = vaddr(&p->from, nil); break; case Z_ib: - v = vaddr(&p->to); case Zib_: + if(t[2] == Zib_) + a = &p->from; + else + a = &p->to; *andptr++ = op; - *andptr++ = v; + *andptr++ = vaddr(a, nil); break; case Zib_rp: rexflag |= regrex[p->to.type] & (Rxb|0x40); *andptr++ = op + reg[p->to.type]; - *andptr++ = v; + *andptr++ = vaddr(&p->from, nil); break; case Zil_rp: rexflag |= regrex[p->to.type] & Rxb; *andptr++ = op + reg[p->to.type]; if(o->prefix == Pe) { + v = vaddr(&p->from, nil); *andptr++ = v; *andptr++ = v>>8; } else - put4(v); + relput4(p, &p->from); break; case Zo_iw: *andptr++ = op; if(p->from.type != D_NONE){ + v = vaddr(&p->from, nil); *andptr++ = v; *andptr++ = v>>8; } break; case Ziq_rp: + v = vaddr(&p->from, &rel); l = v>>32; - if(l == 0){ + if(l == 0 && rel.siz != 8){ //p->mark |= 0100; //print("zero: %llux %P\n", v, p); rexflag &= ~(0x40|Rxw); rexflag |= regrex[p->to.type] & Rxb; *andptr++ = 0xb8 + reg[p->to.type]; + if(rel.type != 0) { + r = addrel(cursym); + *r = rel; + r->off = p->pc + andptr - and; + } put4(v); }else if(l == -1 && (v&((uvlong)1<<31))!=0){ /* sign extend */ //p->mark |= 0100; @@ -1254,6 +1337,11 @@ //print("all: %llux %P\n", v, p); rexflag |= regrex[p->to.type] & Rxb; *andptr++ = op + reg[p->to.type]; + if(rel.type != 0) { + r = addrel(cursym); + *r = rel; + r->off = p->pc + andptr - and; + } put8(v); } break; @@ -1261,53 +1349,54 @@ case Zib_rr: *andptr++ = op; asmand(&p->to, &p->to); - *andptr++ = v; + *andptr++ = vaddr(&p->from, nil); break; case Z_il: - v = vaddr(&p->to); case Zil_: + if(t[2] == Zil_) + a = &p->from; + else + a = &p->to; *andptr++ = op; if(o->prefix == Pe) { + v = vaddr(a, nil); *andptr++ = v; *andptr++ = v>>8; } else - put4(v); + relput4(p, a); break; case Zm_ilo: - v = vaddr(&p->to); + case Zilo_m: *andptr++ = op; - asmando(&p->from, o->op[z+1]); + if(t[2] == Zilo_m) { + a = &p->from; + asmando(&p->to, o->op[z+1]); + } else { + a = &p->to; + asmando(&p->from, o->op[z+1]); + } if(o->prefix == Pe) { + v = vaddr(a, nil); *andptr++ = v; *andptr++ = v>>8; } else - put4(v); - break; - - case Zilo_m: - *andptr++ = op; - asmando(&p->to, o->op[z+1]); - if(o->prefix == Pe) { - *andptr++ = v; - *andptr++ = v>>8; - } - else - put4(v); + relput4(p, a); break; case Zil_rr: *andptr++ = op; asmand(&p->to, &p->to); if(o->prefix == Pe) { + v = vaddr(&p->from, nil); *andptr++ = v; *andptr++ = v>>8; } else - put4(v); + relput4(p, &p->from); break; case Z_rp: @@ -1325,74 +1414,128 @@ asmand(&p->to, &p->to); break; + case Zcall: + q = p->pcond; + if(q == nil) { + diag("call without target"); + errorexit(); + } + if(q->as != ATEXT) { + // Could handle this case by making D_PCREL + // record the Prog* instead of the Sym*, but let's + // wait until the need arises. + diag("call of non-TEXT %P", q); + errorexit(); + } + *andptr++ = op; + r = addrel(cursym); + r->off = p->pc + andptr - and; + r->sym = q->from.sym; + r->type = D_PCREL; + r->siz = 4; + put4(0); + break; + case Zbr: + case Zjmp: + case Zloop: + // TODO: jump across functions needs reloc q = p->pcond; - if(q) { - v = q->pc - p->pc - 2; - if(v >= -128 && v <= 127) { + if(q == nil) { + diag("jmp/branch/loop without target"); + errorexit(); + } + if(q->as == ATEXT) { + if(t[2] == Zbr) { + diag("branch to ATEXT"); + errorexit(); + } + *andptr++ = o->op[z+1]; + r = addrel(cursym); + r->off = p->pc + andptr - and; + r->sym = q->from.sym; + r->type = D_PCREL; + r->siz = 4; + put4(0); + break; + } + // Assumes q is in this function. + // TODO: Check in input, preserve in brchain. + + // Fill in backward jump now. + if(p->back & 1) { + v = q->pc - (p->pc + 2); + if(v >= -128) { + if(p->as == AJCXZL) + *andptr++ = 0x67; *andptr++ = op; *andptr++ = v; + } else if(t[2] == Zloop) { + diag("loop too far: %P", p); } else { - v -= 6-2; - *andptr++ = 0x0f; + v -= 5-2; + if(t[2] == Zbr) { + *andptr++ = 0x0f; + v--; + } *andptr++ = o->op[z+1]; *andptr++ = v; *andptr++ = v>>8; *andptr++ = v>>16; *andptr++ = v>>24; } + break; + } + + // Annotate target; will fill in later. + p->forwd = q->comefrom; + q->comefrom = p; + if(p->back & 2) { // short + if(p->as == AJCXZL) + *andptr++ = 0x67; + *andptr++ = op; + *andptr++ = 0; + } else if(t[2] == Zloop) { + diag("loop too far: %P", p); + } else { + if(t[2] == Zbr) + *andptr++ = 0x0f; + *andptr++ = o->op[z+1]; + *andptr++ = 0; + *andptr++ = 0; + *andptr++ = 0; + *andptr++ = 0; } break; - - case Zcall: - q = p->pcond; - if(q) { - v = q->pc - p->pc - 5; - if(dlm && curp != P && p->to.sym->type == SUNDEF){ - /* v = 0 - p->pc - 5; */ - v = 0; - ckoff(p->to.sym, v); - v += p->to.sym->value; - dynreloc(p->to.sym, p->pc+1, 0); + +/* + v = q->pc - p->pc - 2; + if((v >= -128 && v <= 127) || p->pc == -1 || q->pc == -1) { + *andptr++ = op; + *andptr++ = v; + } else { + v -= 5-2; + if(t[2] == Zbr) { + *andptr++ = 0x0f; + v--; } - *andptr++ = op; + *andptr++ = o->op[z+1]; *andptr++ = v; *andptr++ = v>>8; *andptr++ = v>>16; *andptr++ = v>>24; } - break; - - case Zjmp: - q = p->pcond; - if(q) { - v = q->pc - p->pc - 2; - if(v >= -128 && v <= 127) { - *andptr++ = op; - *andptr++ = v; - } else { - v -= 5-2; - *andptr++ = o->op[z+1]; - *andptr++ = v; - *andptr++ = v>>8; - *andptr++ = v>>16; - *andptr++ = v>>24; - } - } - break; - - case Zloop: - q = p->pcond; - if(q) { - v = q->pc - p->pc - 2; - if(v < -128 && v > 127) - diag("loop too far: %P", p); - *andptr++ = op; - *andptr++ = v; - } +*/ break; case Zbyte: + v = vaddr(&p->from, &rel); + if(rel.siz != 0) { + rel.siz = op; + r = addrel(cursym); + *r = rel; + r->off = p->pc + andptr - and; + } *andptr++ = v; if(op > 1) { *andptr++ = v>>8; @@ -1547,14 +1690,14 @@ case D_CONST: *andptr++ = 0x0f; *andptr++ = t[0]; - asmandsz(&p->to, reg[p->from.index], regrex[p->from.index], 0); + asmandsz(&p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0); *andptr++ = p->from.offset; break; case D_CL: case D_CX: *andptr++ = 0x0f; *andptr++ = t[1]; - asmandsz(&p->to, reg[p->from.index], regrex[p->from.index], 0); + asmandsz(&p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0); break; } break; @@ -1565,6 +1708,7 @@ asmins(Prog *p) { int n, np, c; + Reloc *r; rexflag = 0; andptr = and; @@ -1574,7 +1718,7 @@ /* * as befits the whole approach of the architecture, * the rex prefix must appear before the first opcode byte - * (and thus after any 66/67/f2/f3 prefix bytes, but + * (and thus after any 66/67/f2/f3/26/2e/3e prefix bytes, but * before the 0f opcode escape!), or it might be ignored. * note that the handbook often misleadingly shows 66/f2/f3 in `opcode'. */ @@ -1583,164 +1727,16 @@ n = andptr - and; for(np = 0; np < n; np++) { c = and[np]; - if(c != 0x66 && c != 0xf2 && c != 0xf3 && c != 0x67) + if(c != 0xf2 && c != 0xf3 && (c < 0x64 || c > 0x67) && c != 0x2e && c != 0x3e && c != 0x26) break; } + for(r=cursym->r+cursym->nr; r-- > cursym->r; ) { + if(r->off < p->pc) + break; + r->off++; + } memmove(and+np+1, and+np, n-np); and[np] = 0x40 | rexflag; andptr++; } } - -enum{ - ABSD = 0, - ABSU = 1, - RELD = 2, - RELU = 3, -}; - -int modemap[4] = { 0, 1, -1, 2, }; - -typedef struct Reloc Reloc; - -struct Reloc -{ - int n; - int t; - uchar *m; - ulong *a; -}; - -Reloc rels; - -static void -grow(Reloc *r) -{ - int t; - uchar *m, *nm; - ulong *a, *na; - - t = r->t; - r->t += 64; - m = r->m; - a = r->a; - r->m = nm = malloc(r->t*sizeof(uchar)); - r->a = na = malloc(r->t*sizeof(ulong)); - memmove(nm, m, t*sizeof(uchar)); - memmove(na, a, t*sizeof(ulong)); - free(m); - free(a); -} - -void -dynreloc(Sym *s, ulong v, int abs) -{ - int i, k, n; - uchar *m; - ulong *a; - Reloc *r; - - if(s->type == SUNDEF) - k = abs ? ABSU : RELU; - else - k = abs ? ABSD : RELD; - /* Bprint(&bso, "R %s a=%ld(%lx) %d\n", s->name, v, v, k); */ - k = modemap[k]; - r = &rels; - n = r->n; - if(n >= r->t) - grow(r); - m = r->m; - a = r->a; - for(i = n; i > 0; i--){ - if(v < a[i-1]){ /* happens occasionally for data */ - m[i] = m[i-1]; - a[i] = a[i-1]; - } - else - break; - } - m[i] = k; - a[i] = v; - r->n++; -} - -static int -sput(char *s) -{ - char *p; - - p = s; - while(*s) - cput(*s++); - cput(0); - return s-p+1; -} - -void -asmdyn() -{ - int i, n, t, c; - Sym *s; - ulong la, ra, *a; - vlong off; - uchar *m; - Reloc *r; - - cflush(); - off = seek(cout, 0, 1); - lput(0); - t = 0; - lput(imports); - t += 4; - for(i = 0; i < NHASH; i++) - for(s = hash[i]; s != S; s = s->link) - if(s->type == SUNDEF){ - lput(s->sig); - t += 4; - t += sput(s->name); - } - - la = 0; - r = &rels; - n = r->n; - m = r->m; - a = r->a; - lput(n); - t += 4; - for(i = 0; i < n; i++){ - ra = *a-la; - if(*a < la) - diag("bad relocation order"); - if(ra < 256) - c = 0; - else if(ra < 65536) - c = 1; - else - c = 2; - cput((c<<6)|*m++); - t++; - if(c == 0){ - cput(ra); - t++; - } - else if(c == 1){ - wput(ra); - t += 2; - } - else{ - lput(ra); - t += 4; - } - la = *a++; - } - - cflush(); - seek(cout, off, 0); - lput(t); - - if(debug['v']){ - Bprint(&bso, "import table entries = %d\n", imports); - Bprint(&bso, "export table entries = %d\n", exports); - } -} diff -r d8d00747375b sys/src/cmd/8a/a.h --- a/sys/src/cmd/8a/a.h Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/8a/a.h Mon Nov 14 17:35:25 2011 +0100 @@ -1,27 +1,63 @@ -#include -#include +// Inferno utils/8a/a.h +// http://code.google.com/p/inferno-os/source/browse/utils/8a/a.h +// +// 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 -#include "../8c/8.out.h" +#include "../8l/8.out.h" + #ifndef EXTERN #define EXTERN extern #endif +#undef getc +#undef ungetc +#undef BUFSIZ + +#define getc ccgetc +#define ungetc ccungetc + typedef struct Sym Sym; typedef struct Ref Ref; typedef struct Gen Gen; typedef struct Io Io; typedef struct Hist Hist; -typedef struct Gen2 Gen2; +typedef struct Gen2 Gen2; #define MAXALIGN 7 #define FPCHIP 1 #define NSYMB 500 #define BUFSIZ 8192 #define HISTSZ 20 -#define NINCLUDE 10 -#define NHUNK 10000 +#ifndef EOF #define EOF (-1) +#endif #define IGN (-2) #define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff) #define NHASH 503 @@ -33,7 +69,7 @@ Sym* link; Ref* ref; char* macro; - long value; + int32 value; ushort type; char *name; char sym; @@ -71,7 +107,8 @@ { double dval; char sval[8]; - long offset; + int32 offset; + int32 offset2; Sym* sym; short type; short index; @@ -87,8 +124,8 @@ { Hist* link; char* name; - long line; - long offset; + int32 line; + int32 offset; }; #define H ((Hist*)0) @@ -103,34 +140,38 @@ EXTERN char debug[256]; EXTERN Sym* hash[NHASH]; -EXTERN char* Dlist[30]; +EXTERN char** Dlist; EXTERN int nDlist; EXTERN Hist* ehist; EXTERN int newflag; EXTERN Hist* hist; EXTERN char* hunk; -EXTERN char* include[NINCLUDE]; +EXTERN char** include; EXTERN Io* iofree; EXTERN Io* ionext; EXTERN Io* iostack; -EXTERN long lineno; +EXTERN int32 lineno; EXTERN int nerrors; -EXTERN long nhunk; +EXTERN int32 nhunk; EXTERN int ninclude; +EXTERN int32 nsymb; EXTERN Gen nullgen; EXTERN char* outfile; EXTERN int pass; EXTERN char* pathname; -EXTERN long pc; +EXTERN int32 pc; EXTERN int peekc; +EXTERN int32 stmtline; EXTERN int sym; -EXTERN char symb[NSYMB]; +EXTERN char* symb; EXTERN int thechar; EXTERN char* thestring; -EXTERN long thunk; +EXTERN int32 thunk; EXTERN Biobuf obuf; -void* allocn(void*, long, long); +void* alloc(int32); +void* allocn(void*, int32, int32); +void ensuresymb(int32); void errorexit(void); void pushio(void); void newio(void); @@ -138,7 +179,7 @@ Sym* slookup(char*); Sym* lookup(void); void syminit(Sym*); -long yylex(void); +int32 yylex(void); int getc(void); int getnsc(void); void unget(int); @@ -165,30 +206,10 @@ void macif(int); void macend(void); void dodefine(char*); -void prfile(long); +void prfile(int32); void linehist(char*, int); void gethunk(void); void yyerror(char*, ...); int yyparse(void); void setinclude(char*); int assemble(char*); - -/* - * system-dependent stuff from ../cc/compat.c - */ -enum /* keep in synch with ../cc/cc.h */ -{ - Plan9 = 1<<0, - Unix = 1<<1, - Windows = 1<<2 -}; -int mywait(int*); -int mycreat(char*, int); -int systemtype(int); -int pathchar(void); -char* mygetwd(char*, int); -int myexec(char*, char*[]); -int mydup(int, int); -int myfork(void); -int mypipe(int*); -void* mysbrk(ulong); diff -r d8d00747375b sys/src/cmd/8a/a.y --- a/sys/src/cmd/8a/a.y Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/8a/a.y Mon Nov 14 17:35:25 2011 +0100 @@ -1,9 +1,46 @@ +// Inferno utils/8a/a.y +// http://code.google.com/p/inferno-os/source/browse/utils/8a/a.y +// +// 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 +#include /* if we don't, bison will, and a.h re-#defines getc */ +#include #include "a.h" %} %union { Sym *sym; - long lval; + int32 lval; + struct { + int32 v1; + int32 v2; + } con2; double dval; char sval[8]; Gen gen; @@ -16,19 +53,24 @@ %left '+' '-' %left '*' '/' '%' %token LTYPE0 LTYPE1 LTYPE2 LTYPE3 LTYPE4 -%token LTYPEC LTYPED LTYPEN LTYPER LTYPET LTYPES LTYPEM LTYPEI +%token LTYPEC LTYPED LTYPEN LTYPER LTYPET LTYPES LTYPEM LTYPEI LTYPEG %token LCONST LFP LPC LSB %token LBREG LLREG LSREG LFREG %token LFCONST %token LSCONST LSP %token LNAME LLAB LVAR %type con expr pointer offset -%type mem imm reg nam rel rem rim rom omem nmem +%type con2 +%type mem imm imm2 reg nam rel rem rim rom omem nmem %type nonnon nonrel nonrem rimnon rimrem remrim -%type spec1 spec2 spec3 spec4 spec5 spec6 spec7 +%type spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8 %% prog: -| prog line +| prog + { + stmtline = lineno; + } + line line: LLAB ':' @@ -73,6 +115,7 @@ | LTYPES spec5 { outcode($1, &$2); } | LTYPEM spec6 { outcode($1, &$2); } | LTYPEI spec7 { outcode($1, &$2); } +| LTYPEG spec8 { outcode($1, &$2); } nonnon: { @@ -144,12 +187,12 @@ } spec2: /* TEXT */ - mem ',' imm + mem ',' imm2 { $$.from = $1; $$.to = $3; } -| mem ',' con ',' imm +| mem ',' con ',' imm2 { $$.from = $1; $$.from.scale = $3; @@ -167,6 +210,13 @@ $$.from = nullgen; $$.to = $1; } +| '*' nam + { + $$.from = nullgen; + $$.to = $2; + $$.to.index = $2.type; + $$.to.type = D_INDIR+D_ADDR; + } spec4: /* NOP */ nonnon @@ -219,6 +269,19 @@ $$.to = $3; } +spec8: /* GLOBL */ + mem ',' imm + { + $$.from = $1; + $$.to = $3; + } +| mem ',' con ',' imm + { + $$.from = $1; + $$.from.scale = $3; + $$.to = $5; + } + rem: reg | mem @@ -236,6 +299,7 @@ } | reg | omem +| imm rim: rem @@ -328,6 +392,12 @@ $$.type = D_FCONST; $$.dval = $3; } +| '$' '(' '-' LFCONST ')' + { + $$ = nullgen; + $$.type = D_FCONST; + $$.dval = -$4; + } | '$' '-' LFCONST { $$ = nullgen; @@ -335,6 +405,37 @@ $$.dval = -$3; } +imm2: + '$' con2 + { + $$ = nullgen; + $$.type = D_CONST2; + $$.offset = $2.v1; + $$.offset2 = $2.v2; + } + +con2: + LCONST + { + $$.v1 = $1; + $$.v2 = 0; + } +| '-' LCONST + { + $$.v1 = -$2; + $$.v2 = 0; + } +| LCONST '-' LCONST + { + $$.v1 = $1; + $$.v2 = $3; + } +| '-' LCONST '-' LCONST + { + $$.v1 = -$2; + $$.v2 = $4; + } + mem: omem | nmem @@ -386,6 +487,12 @@ $$ = nullgen; $$.type = D_INDIR+D_SP; } +| con '(' LSREG ')' + { + $$ = nullgen; + $$.type = D_INDIR+$3; + $$.offset = $1; + } | '(' LLREG '*' con ')' { $$ = nullgen; diff -r d8d00747375b sys/src/cmd/8a/l.s --- a/sys/src/cmd/8a/l.s Thu Sep 29 03:00:00 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,704 +0,0 @@ -/* - * Memory and machine-specific definitions. Used in C and assembler. - */ - -/* - * Sizes - */ -#define BI2BY 8 /* bits per byte */ -#define BI2WD 32 /* bits per word */ -#define BY2WD 4 /* bytes per word */ -#define BY2PG 4096 /* bytes per page */ -#define WD2PG (BY2PG/BY2WD) /* words per page */ -#define PGSHIFT 12 /* log(BY2PG) */ -#define PGROUND(s) (((s)+(BY2PG-1))&~(BY2PG-1)) - -#define MAXMACH 1 /* max # cpus system can run */ - -/* - * Time - */ -#define HZ (20) /* clock frequency */ -#define MS2HZ (1000/HZ) /* millisec per clock tick */ -#define TK2SEC(t) ((t)/HZ) /* ticks to seconds */ -#define TK2MS(t) ((((ulong)(t))*1000)/HZ) /* ticks to milliseconds */ -#define MS2TK(t) ((((ulong)(t))*HZ)/1000) /* milliseconds to ticks */ - -/* - * Fundamental addresses - */ - -/* - * Address spaces - * - * User is at 0-2GB - * Kernel is at 2GB-4GB - * - * To avoid an extra page map, both the user stack (USTKTOP) and - * the temporary user stack (TSTKTOP) should be in the the same - * 4 meg. - */ -#define UZERO 0 /* base of user address space */ -#define UTZERO (UZERO+BY2PG) /* first address in user text */ -#define KZERO 0x80000000 /* base of kernel address space */ -#define KTZERO KZERO /* first address in kernel text */ -#define USERADDR 0xC0000000 /* struct User */ -#define UREGADDR (USERADDR+BY2PG-4*19) -#define TSTKTOP USERADDR /* end of new stack in sysexec */ -#define TSTKSIZ 10 -#define USTKTOP (TSTKTOP-TSTKSIZ*BY2PG) /* byte just beyond user stack */ -#define USTKSIZE (16*1024*1024 - TSTKSIZ*BY2PG) /* size of user stack */ -#define ROMBIOS (KZERO|0xF0000) - -#define MACHSIZE 4096 - -#define isphys(x) (((ulong)x)&KZERO) - -/* - * known 80386 segments (in GDT) and their selectors - */ -#define NULLSEG 0 /* null segment */ -#define KDSEG 1 /* kernel data/stack */ -#define KESEG 2 /* kernel executable */ -#define UDSEG 3 /* user data/stack */ -#define UESEG 4 /* user executable */ -#define TSSSEG 5 /* task segment */ - -#define SELGDT (0<<3) /* selector is in gdt */ -#define SELLDT (1<<3) /* selector is in ldt */ - -#define SELECTOR(i, t, p) (((i)<<3) | (t) | (p)) - -#define NULLSEL SELECTOR(NULLSEG, SELGDT, 0) -#define KESEL SELECTOR(KESEG, SELGDT, 0) -#define KDSEL SELECTOR(KDSEG, SELGDT, 0) -#define UESEL SELECTOR(UESEG, SELGDT, 3) -#define UDSEL SELECTOR(UDSEG, SELGDT, 3) -#define TSSSEL SELECTOR(TSSSEG, SELGDT, 0) - -/* - * fields in segment descriptors - */ -#define SEGDATA (0x10<<8) /* data/stack segment */ -#define SEGEXEC (0x18<<8) /* executable segment */ -#define SEGTSS (0x9<<8) /* TSS segment */ -#define SEGCG (0x0C<<8) /* call gate */ -#define SEGIG (0x0E<<8) /* interrupt gate */ -#define SEGTG (0x0F<<8) /* task gate */ -#define SEGTYPE (0x1F<<8) - -#define SEGP (1<<15) /* segment present */ -#define SEGPL(x) ((x)<<13) /* priority level */ -#define SEGB (1<<22) /* granularity 1==4k (for expand-down) */ -#define SEGG (1<<23) /* granularity 1==4k (for other) */ -#define SEGE (1<<10) /* expand down */ -#define SEGW (1<<9) /* writable (for data/stack) */ -#define SEGR (1<<9) /* readable (for code) */ -#define SEGD (1<<22) /* default 1==32bit (for code) */ - -/* - * virtual MMU - */ -#define PTEMAPMEM (1024*1024) /* ??? */ -#define SEGMAPSIZE 16 /* ??? */ -#define PTEPERTAB (PTEMAPMEM/BY2PG) /* ??? */ -#define PPN(x) ((x)&~(BY2PG-1)) - -/* - * physical MMU - */ -#define PTEVALID (1<<0) -#define PTEUNCACHED 0 /* everything is uncached */ -#define PTEWRITE (1<<1) -#define PTERONLY (0<<1) -#define PTEKERNEL (0<<2) -#define PTEUSER (1<<2) - -/* - * flag register bits that we care about - */ -#define IFLAG 0x200 - -#define OP16 BYTE $0x66 - -/* - * about to walk all over ms/dos - turn off interrupts - */ -TEXT origin(SB),$0 - - CLI - -#ifdef BOOT -/* - * This part of l.s is used only in the boot kernel. - * It assumes that we are in real address mode, i.e., - * that we look like an 8086. - */ -/* - * relocate everything to a half meg and jump there - * - looks wierd because it is being assembled by a 32 bit - * assembler for a 16 bit world - */ - MOVL $0,BX - INCL BX - SHLL $15,BX - MOVL BX,CX - MOVW BX,ES - MOVL $0,SI - MOVL SI,DI - CLD; REP; MOVSL -/* JMPFAR 0X8000:$lowcore(SB) /**/ - BYTE $0xEA - WORD $lowcore(SB) - WORD $0X8000 - -TEXT lowcore(SB),$0 - -/* - * now that we're in low core, update the DS - */ - - MOVW BX,DS - -/* - * goto protected mode - */ -/* MOVL tgdtptr(SB),GDTR /**/ - BYTE $0x0f - BYTE $0x01 - BYTE $0x16 - WORD $tgdtptr(SB) - MOVL CR0,AX - ORL $1,AX - MOVL AX,CR0 - -/* - * clear prefetch queue (wierd code to avoid optimizations) - */ - CLC - JCC flush - MOVL AX,AX -flush: - -/* - * set all segs - */ -/* MOVW $SELECTOR(1, SELGDT, 0),AX /**/ - BYTE $0xc7 - BYTE $0xc0 - WORD $SELECTOR(1, SELGDT, 0) - MOVW AX,DS - MOVW AX,SS - MOVW AX,ES - MOVW AX,FS - MOVW AX,GS - -/* JMPFAR SELECTOR(2, SELGDT, 0):$mode32bit(SB) /**/ - BYTE $0x66 - BYTE $0xEA - LONG $mode32bit-KZERO(SB) - WORD $SELECTOR(2, SELGDT, 0) - -TEXT mode32bit(SB),$0 - -#endif BOOT - - /* - * Clear BSS - */ - LEAL edata-KZERO(SB),SI - MOVL SI,DI - ADDL $4,DI - MOVL $0,AX - MOVL AX,(SI) - LEAL end-KZERO(SB),CX - SUBL DI,CX - SHRL $2,CX - CLD; REP; MOVSL - - /* - * make a bottom level page table page that maps the first - * 16 meg of physical memory - */ - LEAL tpt-KZERO(SB),AX /* get phys addr of temporary page table */ - ADDL $(BY2PG-1),AX /* must be page alligned */ - ANDL $(~(BY2PG-1)),AX /* ... */ - MOVL $(4*1024),CX /* pte's per page */ - MOVL $((((4*1024)-1)<>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+0)(AX) - ADDL $BY2PG,BX - MOVL BX,4(AX) - MOVL BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+4)(AX) - ADDL $BY2PG,BX - MOVL BX,8(AX) - MOVL BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+8)(AX) - ADDL $BY2PG,BX - MOVL BX,12(AX) - MOVL BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+12)(AX) - - /* - * point processor to top level page & turn on paging - */ - MOVL AX,CR3 - MOVL CR0,AX - ORL $0X80000000,AX - ANDL $~(0x8|0x2),AX /* TS=0, MP=0 */ - MOVL AX,CR0 - - /* - * use a jump to an absolute location to get the PC into - * KZERO. - */ - LEAL tokzero(SB),AX - JMP* AX - -TEXT tokzero(SB),$0 - - /* - * stack and mach - */ - MOVL $mach0(SB),SP - MOVL SP,m(SB) - MOVL $0,0(SP) - ADDL $(MACHSIZE-4),SP /* start stack under machine struct */ - MOVL $0, u(SB) - - /* - * clear flags - */ - MOVL $0,AX - PUSHL AX - POPFL - - CALL main(SB) - -loop: - JMP loop - -GLOBL mach0+0(SB), $MACHSIZE -GLOBL u(SB), $4 -GLOBL m(SB), $4 -GLOBL tpt(SB), $(BY2PG*6) - -/* - * gdt to get us to 32-bit/segmented/unpaged mode - */ -TEXT tgdt(SB),$0 - - /* null descriptor */ - LONG $0 - LONG $0 - - /* data segment descriptor for 4 gigabytes (PL 0) */ - LONG $(0xFFFF) - LONG $(SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(0)|SEGDATA|SEGW) - - /* exec segment descriptor for 4 gigabytes (PL 0) */ - LONG $(0xFFFF) - LONG $(SEGG|SEGD|(0xF<<16)|SEGP|SEGPL(0)|SEGEXEC|SEGR) - -/* - * pointer to initial gdt - */ -TEXT tgdtptr(SB),$0 - - WORD $(3*8) - LONG $tgdt-KZERO(SB) - -/* - * input a byte - */ -TEXT inb(SB),$0 - - MOVL p+0(FP),DX - XORL AX,AX - INB - RET - -/* - * output a byte - */ -TEXT outb(SB),$0 - - MOVL p+0(FP),DX - MOVL b+4(FP),AX - OUTB - RET - -/* - * input a string of shorts from a port - */ -TEXT inss(SB),$0 - MOVL p+0(FP),DX - MOVL a+4(FP),DI - MOVL c+8(FP),CX - CLD; REP; OP16; INSL - RET - -/* - * output a string of shorts to a port - */ -TEXT outss(SB),$0 - MOVL p+0(FP),DX - MOVL a+4(FP),SI - MOVL c+8(FP),CX - CLD; REP; OP16; OUTSL - RET - -/* - * test and set - */ -TEXT tas(SB),$0 - MOVL $0xdeadead,AX - MOVL l+0(FP),BX - XCHGL AX,(BX) - RET - -/* - * routines to load/read various system registers - */ -GLOBL idtptr(SB),$6 -TEXT putidt(SB),$0 /* interrupt descriptor table */ - MOVL t+0(FP),AX - MOVL AX,idtptr+2(SB) - MOVL l+4(FP),AX - MOVW AX,idtptr(SB) - MOVL idtptr(SB),IDTR - RET - -GLOBL gdtptr(SB),$6 -TEXT putgdt(SB),$0 /* global descriptor table */ - MOVL t+0(FP),AX - MOVL AX,gdtptr+2(SB) - MOVL l+4(FP),AX - MOVW AX,gdtptr(SB) - MOVL gdtptr(SB),GDTR - RET - -TEXT putcr3(SB),$0 /* top level page table pointer */ - MOVL t+0(FP),AX - MOVL AX,CR3 - RET - -TEXT puttr(SB),$0 /* task register */ - MOVL t+0(FP),AX - MOVW AX,TASK - RET - -TEXT getcr0(SB),$0 /* coprocessor bits */ - MOVL CR0,AX - RET - -TEXT getcr2(SB),$0 /* fault address */ - MOVL CR2,AX - RET - -#define FPOFF\ - WAIT;\ - MOVL CR0,AX;\ - ORL $0x4,AX /* EM=1 */;\ - MOVL AX,CR0 - -#define FPON\ - MOVL CR0,AX;\ - ANDL $~0x4,AX /* EM=0 */;\ - MOVL AX,CR0 - -TEXT fpoff(SB),$0 /* turn off floating point */ - FPOFF - RET - -TEXT fpinit(SB),$0 /* turn on & init the floating point */ - FPON - FINIT - WAIT - PUSHW $0x0330 - FLDCW 0(SP) /* ignore underflow/precision, signal others */ - POPW AX - WAIT - RET - -TEXT fpsave(SB),$0 /* save floating point state and turn off */ - MOVL p+0(FP),AX - WAIT - FSAVE 0(AX) - FPOFF - RET - -TEXT fprestore(SB),$0 /* turn on floating point and restore regs */ - FPON - MOVL p+0(FP),AX - FRSTOR 0(AX) - WAIT - RET - -TEXT fpstatus(SB),$0 /* get floating point status */ - FSTSW AX - RET - -/* - * special traps - */ -TEXT intr0(SB),$0 - PUSHL $0 - PUSHL $0 - JMP intrcommon -TEXT intr1(SB),$0 - PUSHL $0 - PUSHL $1 - JMP intrcommon -TEXT intr2(SB),$0 - PUSHL $0 - PUSHL $2 - JMP intrcommon -TEXT intr3(SB),$0 - PUSHL $0 - PUSHL $3 - JMP intrcommon -TEXT intr4(SB),$0 - PUSHL $0 - PUSHL $4 - JMP intrcommon -TEXT intr5(SB),$0 - PUSHL $0 - PUSHL $5 - JMP intrcommon -TEXT intr6(SB),$0 - PUSHL $0 - PUSHL $6 - JMP intrcommon -TEXT intr7(SB),$0 - PUSHL $0 - PUSHL $7 - JMP intrcommon -TEXT intr8(SB),$0 - PUSHL $8 - JMP intrscommon -TEXT intr9(SB),$0 - PUSHL $0 - PUSHL $9 - JMP intrcommon -TEXT intr10(SB),$0 - PUSHL $10 - JMP intrscommon -TEXT intr11(SB),$0 - PUSHL $11 - JMP intrscommon -TEXT intr12(SB),$0 - PUSHL $12 - JMP intrscommon -TEXT intr13(SB),$0 - PUSHL $13 - JMP intrscommon -TEXT intr14(SB),$0 - PUSHL $14 - JMP intrscommon -TEXT intr15(SB),$0 - PUSHL $0 - PUSHL $15 - JMP intrcommon -TEXT intr16(SB),$0 - PUSHL $0 - PUSHL $16 - JMP intrcommon -TEXT intr24(SB),$0 - PUSHL $0 - PUSHL $24 - JMP intrcommon -TEXT intr25(SB),$0 - PUSHL $0 - PUSHL $25 - JMP intrcommon -TEXT intr26(SB),$0 - PUSHL $0 - PUSHL $26 - JMP intrcommon -TEXT intr27(SB),$0 - PUSHL $0 - PUSHL $27 - JMP intrcommon -TEXT intr28(SB),$0 - PUSHL $0 - PUSHL $28 - JMP intrcommon -TEXT intr29(SB),$0 - PUSHL $0 - PUSHL $29 - JMP intrcommon -TEXT intr30(SB),$0 - PUSHL $0 - PUSHL $30 - JMP intrcommon -TEXT intr31(SB),$0 - PUSHL $0 - PUSHL $31 - JMP intrcommon -TEXT intr32(SB),$0 - PUSHL $0 - PUSHL $16 - JMP intrcommon -TEXT intr33(SB),$0 - PUSHL $0 - PUSHL $33 - JMP intrcommon -TEXT intr34(SB),$0 - PUSHL $0 - PUSHL $34 - JMP intrcommon -TEXT intr35(SB),$0 - PUSHL $0 - PUSHL $35 - JMP intrcommon -TEXT intr36(SB),$0 - PUSHL $0 - PUSHL $36 - JMP intrcommon -TEXT intr37(SB),$0 - PUSHL $0 - PUSHL $37 - JMP intrcommon -TEXT intr38(SB),$0 - PUSHL $0 - PUSHL $38 - JMP intrcommon -TEXT intr39(SB),$0 - PUSHL $0 - PUSHL $39 - JMP intrcommon -TEXT intr64(SB),$0 - PUSHL $0 - PUSHL $64 - JMP intrcommon -TEXT intrbad(SB),$0 - PUSHL $0 - PUSHL $0x1ff - JMP intrcommon - -intrcommon: - PUSHL DS - PUSHL ES - PUSHL FS - PUSHL GS - PUSHAL - MOVL $(KDSEL),AX - MOVW AX,DS - MOVW AX,ES - LEAL 0(SP),AX - PUSHL AX - CALL trap(SB) - POPL AX - POPAL - POPL GS - POPL FS - POPL ES - POPL DS - ADDL $8,SP /* error code and trap type */ - IRETL - -intrscommon: - PUSHL DS - PUSHL ES - PUSHL FS - PUSHL GS - PUSHAL - MOVL $(KDSEL),AX - MOVW AX,DS - MOVW AX,ES - LEAL 0(SP),AX - PUSHL AX - CALL trap(SB) - POPL AX - POPAL - POPL GS - POPL FS - POPL ES - POPL DS - ADDL $8,SP /* error code and trap type */ - IRETL - -/* - * interrupt level is interrupts on or off - */ -TEXT spllo(SB),$0 - PUSHFL - POPL AX - STI - RET - -TEXT splhi(SB),$0 - PUSHFL - POPL AX - CLI - RET - -TEXT splx(SB),$0 - MOVL s+0(FP),AX - PUSHL AX - POPFL - RET - -/* - * do nothing whatsoever till interrupt happens - */ -TEXT idle(SB),$0 - HLT - RET - -/* - * label consists of a stack pointer and a PC - */ -TEXT gotolabel(SB),$0 - MOVL l+0(FP),AX - MOVL 0(AX),SP /* restore sp */ - MOVL 4(AX),AX /* put return pc on the stack */ - MOVL AX,0(SP) - MOVL $1,AX /* return 1 */ - RET - -TEXT setlabel(SB),$0 - MOVL l+0(FP),AX - MOVL SP,0(AX) /* store sp */ - MOVL 0(SP),BX /* store return pc */ - MOVL BX,4(AX) - MOVL $0,AX /* return 0 */ - RET - -/* - * Used to get to the first process. - * Set up an interrupt return frame and IRET to user level. - */ -TEXT touser(SB),$0 - PUSHL $(UDSEL) /* old ss */ - PUSHL $(USTKTOP) /* old sp */ - PUSHFL /* old flags */ - PUSHL $(UESEL) /* old cs */ - PUSHL $(UTZERO+32) /* old pc */ - MOVL $(UDSEL),AX - MOVW AX,DS - MOVW AX,ES - MOVW AX,GS - MOVW AX,FS - IRETL - -/* - * set configuration register - */ -TEXT config(SB),$0 - MOVL l+0(FP),AX - MOVL $0x3F3,DX - OUTB - OUTB - RET diff -r d8d00747375b sys/src/cmd/8a/lex.c --- a/sys/src/cmd/8a/lex.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/8a/lex.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,20 +1,76 @@ -#include +// Inferno utils/8a/lex.c +// http://code.google.com/p/inferno-os/source/browse/utils/8a/lex.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. + #define EXTERN +#include +#include #include "a.h" #include "y.tab.h" +enum +{ + Plan9 = 1<<0, + Unix = 1<<1, + Windows = 1<<2, +}; + +int +systemtype(int sys) +{ +#ifdef _WIN32 + return sys&Windows; +#else + return sys&Plan9; +#endif +} + +int +pathchar(void) +{ + return '/'; +} + void main(int argc, char *argv[]) { char *p; - int nout, nproc, status, i, c; + int c; thechar = '8'; thestring = "386"; + + ensuresymb(NSYMB); memset(debug, 0, sizeof(debug)); cinit(); outfile = 0; - include[ninclude++] = "."; + setinclude("."); ARGBEGIN { default: c = ARGC(); @@ -28,8 +84,12 @@ case 'D': p = ARGF(); - if(p) + if(p) { + if (nDlist%8 == 0) + Dlist = allocn(Dlist, nDlist*sizeof(char *), + 8*sizeof(char *)); Dlist[nDlist++] = p; + } break; case 'I': @@ -41,49 +101,10 @@ print("usage: %ca [-options] file.s\n", thechar); errorexit(); } - if(argc > 1 && systemtype(Windows)){ - print("can't assemble multiple files on windows\n"); + if(argc > 1){ + print("can't assemble multiple files\n"); errorexit(); } - if(argc > 1 && !systemtype(Windows)) { - nproc = 1; - if(p = getenv("NPROC")) - nproc = atol(p); /* */ - c = 0; - nout = 0; - for(;;) { - while(nout < nproc && argc > 0) { - i = myfork(); - if(i < 0) { - i = mywait(&status); - if(i < 0) - errorexit(); - if(status) - c++; - nout--; - continue; - } - if(i == 0) { - print("%s:\n", *argv); - if(assemble(*argv)) - errorexit(); - exits(0); - } - nout++; - argc--; - argv++; - } - i = mywait(&status); - if(i < 0) { - if(c) - errorexit(); - exits(0); - } - if(status) - c++; - nout--; - } - } if(assemble(argv[0])) errorexit(); exits(0); @@ -92,9 +113,10 @@ int assemble(char *file) { - char ofile[100], incfile[20], *p; + char *ofile, incfile[20], *p; int i, of; + ofile = alloc(strlen(file)+3); // +3 for .x\0 (x=thechar) strcpy(ofile, file); p = utfrrune(ofile, pathchar()); if(p) { @@ -126,7 +148,7 @@ } } - of = mycreat(outfile, 0664); + of = create(outfile, OWRITE, 0664); if(of < 0) { yyerror("%ca: cannot create %s", thechar, outfile); errorexit(); @@ -135,6 +157,9 @@ pass = 1; pinit(file); + + Bprint(&obuf, "go object %s %s %s\n", getgoos(), thestring, getgoversion()); + for(i=0; i>16); Bputc(&obuf, l>>24); } + if(t & T_OFFSET2) { + l = a->offset2; + Bputc(&obuf, l); + Bputc(&obuf, l>>8); + Bputc(&obuf, l>>16); + Bputc(&obuf, l>>24); + } if(t & T_SYM) /* implies sym */ Bputc(&obuf, s); if(t & T_FCONST) { @@ -809,10 +900,10 @@ } Bputc(&obuf, a); Bputc(&obuf, a>>8); - Bputc(&obuf, lineno); - Bputc(&obuf, lineno>>8); - Bputc(&obuf, lineno>>16); - Bputc(&obuf, lineno>>24); + Bputc(&obuf, stmtline); + Bputc(&obuf, stmtline>>8); + Bputc(&obuf, stmtline>>16); + Bputc(&obuf, stmtline>>24); zaddr(&g2->from, sf); zaddr(&g2->to, st); @@ -834,17 +925,13 @@ for(h = hist; h != H; h = h->link) { p = h->name; op = 0; - /* on windows skip drive specifier in pathname */ if(systemtype(Windows) && p && p[1] == ':'){ - p += 2; - c = *p; - } - if(p && p[0] != c && h->offset == 0 && pathname){ - /* on windows skip drive specifier in pathname */ + c = p[2]; + } else if(p && p[0] != c && h->offset == 0 && pathname){ if(systemtype(Windows) && pathname[1] == ':') { op = p; - p = pathname+2; - c = *p; + p = pathname; + c = p[2]; } else if(pathname[0] == c){ op = p; p = pathname; @@ -893,4 +980,3 @@ #include "../cc/lexbody" #include "../cc/macbody" -#include "../cc/compat" diff -r d8d00747375b sys/src/cmd/8a/mkfile --- a/sys/src/cmd/8a/mkfile Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/8a/mkfile Mon Nov 14 17:35:25 2011 +0100 @@ -6,7 +6,7 @@ lex.$O\ HFILES=\ - ../8c/8.out.h\ + ../8l/8.out.h\ y.tab.h\ a.h\ @@ -23,4 +23,4 @@ < /sys/src/cmd/mkone YFLAGS=-D1 -d -lex.$O: ../cc/macbody ../cc/lexbody ../cc/compat +lex.$O: ../cc/macbody ../cc/lexbody #../cc/compat diff -r d8d00747375b sys/src/cmd/8c/8.out.h --- a/sys/src/cmd/8c/8.out.h Thu Sep 29 03:00:00 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,445 +0,0 @@ -#define NSYM 50 -#define NSNAME 8 -#define NOPROF (1<<0) -#define DUPOK (1<<1) - -enum as -{ - AXXX, - AAAA, - AAAD, - AAAM, - AAAS, - AADCB, - AADCL, - AADCW, - AADDB, - AADDL, - AADDW, - AADJSP, - AANDB, - AANDL, - AANDW, - AARPL, - ABOUNDL, - ABOUNDW, - ABSFL, - ABSFW, - ABSRL, - ABSRW, - ABTL, - ABTW, - ABTCL, - ABTCW, - ABTRL, - ABTRW, - ABTSL, - ABTSW, - ABYTE, - ACALL, - ACLC, - ACLD, - ACLI, - ACLTS, - ACMC, - ACMPB, - ACMPL, - ACMPW, - ACMPSB, - ACMPSL, - ACMPSW, - ADAA, - ADAS, - ADATA, - ADECB, - ADECL, - ADECW, - ADIVB, - ADIVL, - ADIVW, - AENTER, - AGLOBL, - AGOK, - AHISTORY, - AHLT, - AIDIVB, - AIDIVL, - AIDIVW, - AIMULB, - AIMULL, - AIMULW, - AINB, - AINL, - AINW, - AINCB, - AINCL, - AINCW, - AINSB, - AINSL, - AINSW, - AINT, - AINTO, - AIRETL, - AIRETW, - AJCC, - AJCS, - AJCXZ, - AJEQ, - AJGE, - AJGT, - AJHI, - AJLE, - AJLS, - AJLT, - AJMI, - AJMP, - AJNE, - AJOC, - AJOS, - AJPC, - AJPL, - AJPS, - ALAHF, - ALARL, - ALARW, - ALEAL, - ALEAW, - ALEAVEL, - ALEAVEW, - ALOCK, - ALODSB, - ALODSL, - ALODSW, - ALONG, - ALOOP, - ALOOPEQ, - ALOOPNE, - ALSLL, - ALSLW, - AMOVB, - AMOVL, - AMOVW, - AMOVBLSX, - AMOVBLZX, - AMOVBWSX, - AMOVBWZX, - AMOVWLSX, - AMOVWLZX, - AMOVSB, - AMOVSL, - AMOVSW, - AMULB, - AMULL, - AMULW, - ANAME, - ANEGB, - ANEGL, - ANEGW, - ANOP, - ANOTB, - ANOTL, - ANOTW, - AORB, - AORL, - AORW, - AOUTB, - AOUTL, - AOUTW, - AOUTSB, - AOUTSL, - AOUTSW, - APOPAL, - APOPAW, - APOPFL, - APOPFW, - APOPL, - APOPW, - APUSHAL, - APUSHAW, - APUSHFL, - APUSHFW, - APUSHL, - APUSHW, - ARCLB, - ARCLL, - ARCLW, - ARCRB, - ARCRL, - ARCRW, - AREP, - AREPN, - ARET, - AROLB, - AROLL, - AROLW, - ARORB, - ARORL, - ARORW, - ASAHF, - ASALB, - ASALL, - ASALW, - ASARB, - ASARL, - ASARW, - ASBBB, - ASBBL, - ASBBW, - ASCASB, - ASCASL, - ASCASW, - ASETCC, - ASETCS, - ASETEQ, - ASETGE, - ASETGT, - ASETHI, - ASETLE, - ASETLS, - ASETLT, - ASETMI, - ASETNE, - ASETOC, - ASETOS, - ASETPC, - ASETPL, - ASETPS, - ACDQ, - ACWD, - ASHLB, - ASHLL, - ASHLW, - ASHRB, - ASHRL, - ASHRW, - ASTC, - ASTD, - ASTI, - ASTOSB, - ASTOSL, - ASTOSW, - ASUBB, - ASUBL, - ASUBW, - ASYSCALL, - ATESTB, - ATESTL, - ATESTW, - ATEXT, - AVERR, - AVERW, - AWAIT, - AWORD, - AXCHGB, - AXCHGL, - AXCHGW, - AXLAT, - AXORB, - AXORL, - AXORW, - - AFMOVB, - AFMOVBP, - AFMOVD, - AFMOVDP, - AFMOVF, - AFMOVFP, - AFMOVL, - AFMOVLP, - AFMOVV, - AFMOVVP, - AFMOVW, - AFMOVWP, - AFMOVX, - AFMOVXP, - - AFCOMB, - AFCOMBP, - AFCOMD, - AFCOMDP, - AFCOMDPP, - AFCOMF, - AFCOMFP, - AFCOML, - AFCOMLP, - AFCOMW, - AFCOMWP, - AFUCOM, - AFUCOMP, - AFUCOMPP, - - AFADDDP, - AFADDW, - AFADDL, - AFADDF, - AFADDD, - - AFMULDP, - AFMULW, - AFMULL, - AFMULF, - AFMULD, - - AFSUBDP, - AFSUBW, - AFSUBL, - AFSUBF, - AFSUBD, - - AFSUBRDP, - AFSUBRW, - AFSUBRL, - AFSUBRF, - AFSUBRD, - - AFDIVDP, - AFDIVW, - AFDIVL, - AFDIVF, - AFDIVD, - - AFDIVRDP, - AFDIVRW, - AFDIVRL, - AFDIVRF, - AFDIVRD, - - AFXCHD, - AFFREE, - - AFLDCW, - AFLDENV, - AFRSTOR, - AFSAVE, - AFSTCW, - AFSTENV, - AFSTSW, - - AF2XM1, - AFABS, - AFCHS, - AFCLEX, - AFCOS, - AFDECSTP, - AFINCSTP, - AFINIT, - AFLD1, - AFLDL2E, - AFLDL2T, - AFLDLG2, - AFLDLN2, - AFLDPI, - AFLDZ, - AFNOP, - AFPATAN, - AFPREM, - AFPREM1, - AFPTAN, - AFRNDINT, - AFSCALE, - AFSIN, - AFSINCOS, - AFSQRT, - AFTST, - AFXAM, - AFXTRACT, - AFYL2X, - AFYL2XP1, - - AEND, - - ADYNT, - AINIT, - - ASIGNAME, - - ALAST -}; - -enum -{ - D_AL = 0, - D_CL, - D_DL, - D_BL, - - D_AH = 4, - D_CH, - D_DH, - D_BH, - - D_AX = 8, - D_CX, - D_DX, - D_BX, - D_SP, - D_BP, - D_SI, - D_DI, - - D_F0 = 16, - - D_CS = 24, - D_SS, - D_DS, - D_ES, - D_FS, - D_GS, - - D_GDTR, /* global descriptor table register */ - D_IDTR, /* interrupt descriptor table register */ - D_LDTR, /* local descriptor table register */ - D_MSW, /* machine status word */ - D_TASK, /* task register */ - - D_CR = 35, - D_DR = 43, - D_TR = 51, - - D_NONE = 59, - - D_BRANCH = 60, - D_EXTERN = 61, - D_STATIC = 62, - D_AUTO = 63, - D_PARAM = 64, - D_CONST = 65, - D_FCONST = 66, - D_SCONST = 67, - D_ADDR = 68, - - D_FILE, - D_FILE1, - - D_INDIR, /* additive */ - - T_TYPE = 1<<0, - T_INDEX = 1<<1, - T_OFFSET = 1<<2, - T_FCONST = 1<<3, - T_SYM = 1<<4, - T_SCONST = 1<<5, - - REGARG = -1, - REGRET = D_AX, - FREGRET = D_F0, - REGSP = D_SP, - REGTMP = D_DI, -}; - -/* - * this is the ranlib header - */ -#define SYMDEF "__.SYMDEF" - -/* - * this is the simulated IEEE floating point - */ -typedef struct ieee Ieee; -struct ieee -{ - long l; /* contains ls-man 0xffffffff */ - long h; /* contains sign 0x80000000 - exp 0x7ff00000 - ms-man 0x000fffff */ -}; diff -r d8d00747375b sys/src/cmd/8c/bound.c --- a/sys/src/cmd/8c/bound.c Thu Sep 29 03:00:00 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1117 +0,0 @@ -#include "gc.h" -#include "bound.h" - -static BB* bbfree; -static BBset* bbsfree; -static int bballoc; -static int bbsalloc; -static BB bbz; -static BBset bbsz; -static BB* firstbb; -static BB* lastbb; -static BB* wounded; -static BB* bbaux; -static BBset* recalc; -static BBset* bbhash[BBHASH]; -static BB** ordered; -static int bcount; -static BBset** heap; -static int heapn; -static int bsize; -static char bbbuff[BBBSIZE]; -static int bchange; - -#define bdebug (debug['v']) -#define dbg 0 -#define bcheck 0 - -static long -Rn(Reg *r) -{ - if(r == R) - return -1; - return r->rpo; -} - -static BB* -bba(void) -{ - BB *b; - - bballoc++; - b = bbfree; - if(b == nil) { - b = alloc(sizeof(*b)); - } else - bbfree = b->link; - - *b = bbz; - return b; -} - -static void -bfree(BB *b) -{ - bballoc--; - b->link = bbfree; - bbfree = b; -} - -static BBset* -bbsa(void) -{ - BBset *b; - - bballoc++; - b = bbsfree; - if(b == nil) { - b = alloc(sizeof(*b)); - } else - bbsfree = b->link; - - *b = bbsz; - return b; -} - -static void -bsfree(BBset *b) -{ - bballoc--; - b->link = bbsfree; - bbsfree = b; -} - -static void -dumpheap(void) -{ - int i; - - for(i = 1; i <= heapn; i++) - print(" %d", heap[i]->damage); -} - -static void -checkheap(void) -{ - int N, N2, n, c; - - N = heapn; - N2 = N >> 1; - for(n = 1; n <= N2; n++) { - c = n << 1; - if((heap[c]->damage > heap[n]->damage) - || ((c < N) && (heap[c + 1]->damage > heap[n]->damage))) { - print("bad heap (%d:%d) %d [", n, heap[n]->damage, heapn); - dumpheap(); - print(" ]\n"); - abort(); - } - } -} - -static void -downheap(int n) -{ - int N, N2, d, c; - BBset *s, *t, *u; - - s = heap[n]; - d = s->damage; -//print("down %d %d", n, d); - N = heapn; - N2 = N >> 1; - while(n <= N2) { - c = n << 1; - t = heap[c]; - if(c < N) { - u = heap[c + 1]; - if(t->damage < u->damage) { - t = u; - c++; - } - } -//print(" [%d %d]", c, t->damage); - if(t->damage < d) - break; - heap[n] = t; - t->index = n; - n = c; - } - heap[n] = s; - s->index = n; -//print("\n"); -//checkheap(); -} - -static void -upheap(int n) -{ - int f, d; - BBset *s, *t; - - s = heap[n]; - d = s->damage; -//print("up %d %d", n, d); - while(n > 1) { - f = n >> 1; - t = heap[f]; -//print(" [%d %d]", f, t->damage); - if(t->damage >= d) - break; - heap[n] = t; - t->index = n; - n = f; - } - heap[n] = s; - s->index = n; -//print("\n"); -//checkheap(); -} - -static void -heapremove(BBset *s) -{ - int x; - BBset *t; - - x = s->index; - s->index = 0; - if(x == 0) - return; - if(x == heapn) { - heapn--; - return; - } - t = heap[heapn--]; - heap[x] = t; - t->index = x; - if(s->damage < t->damage) - upheap(x); - else - downheap(x); -} - -static void -heapadd(BBset *s) -{ - int n; - - n = heapn + 1; - heap[n] = s; - s->index = n; - heapn = n; - upheap(n); - -} - -static void -bbsrecalc(BBset *s) -{ - if(s->recalc) - return; - s->recalc = 1; - s->link = recalc; - recalc = s; - heapremove(s); -} - -static void -bbadd(BB *b, Hval h) -{ - int k; - BBset *s; - - k = h[0] & BBMASK; - for(s = bbhash[k]; s != nil; s = s->next) { - if(BBEQ(s->hash, h)) { - b->set = s; - b->link = s->ents; - s->ents = b; - bbsrecalc(s); - return; - } - } - s = bbsa(); - s->next = bbhash[k]; - bbhash[k] = s; - b->set = s; - b->link = nil; - s->ents = b; - BBCP(s->hash, h); - bbsrecalc(s); -} - -static int -hashbb(BB *b, Hval h) -{ - Reg *r; - Prog *p; - char *s; - int c, f, i, n; - - r = b->first; - s = bbbuff; - i = 0; - n = BBBSIZE; - for(;;) { - p = r->prog; - if(p->as != ANOP) { - if(p->to.type == D_BRANCH) - p->to.offset = r->s2->rpo; - c = snprint(s, n, "%P", p); - s += c; - n -= c; - i++; - } - if(r == b->last) - break; - r = r->link; - } - if(n == 0) - return Bbig; - b->len = i; - BBMKHASH(bbbuff, BBBSIZE - n, h); - f = b->flags; - if(i == 1 && r->prog->as == AJMP && b->first->p1 == R) - f = Bjo; - else if(b->first->p1 != R) - f |= Bpre; - if(bdebug) - print("A %x %s %ux %ux\n", f, bbbuff, h[0], h[1]); - return f; -} - -static void -enterbb(BB *b) -{ - Hval h; - - b->flags = hashbb(b, h); - if(b->flags != Bbig) - bbadd(b, h); -} - -static void -preproc(BB *b, int x) -{ - BB *n; - Reg *r; - - ordered[x] = b; - if(b->last->rpo - b->first->rpo > BBBIG) { - b->flags = Bbig; - return; - } - if(b->first->p2 == nil) { - b->flags = Bdel; - return; - } - switch(b->last->prog->as) { - case ARET: - case AJMP: - case AIRETL: - break; - - default: - b->flags = Bdel; - n = bba(); - n->first = b->first; - for(r = b->last->link; r != R; r = r->link) { - switch(r->prog->as) { - case ARET: - case AJMP: - case AIRETL: - n->last = r; - n->flags = Bpin; - enterbb(n); - if(n->flags & Bpin) { - n->aux = bbaux; - bbaux = n; - } - else - bfree(n); - return; - } - } - bfree(n); - return; - } - enterbb(b); -} - -static int -p2len(Reg *r) -{ - int c; - - c = 0; - for(r = r->p2; r != nil; r = r->p2link) - c++; - return c; -} - -static void -calcdamage(BBset *s) -{ - BB *f; - int d, t; - - s->recalc = 0; - f = s->ents; - if(f == nil) - return; - if(f->flags & Bjo) { - if(bdebug) - print("add %ld jo\n", f->first->rpo); - s->damage = COSTJO; - heapadd(s); - return; - } - if(f->link == nil) { - if(bdebug) - print("solo %x %x\n", s->hash[0], s->hash[1]); - return; - } - - d = 0; - t = 0; - while(f != nil) { - if((f->flags & (Bpre|Bpin)) == 0 && f->last->link != R) { - t = 1; - d += (f->last->rpo - f->first->rpo) >> 1; - } - d += p2len(f->first); - f = f->link; - } - - if(t == 0) { - if(bdebug) - print("all pre %ld\n", s->ents->first->rpo); - return; - } - - if(bdebug) - print("add %ld %d\n", s->ents->first->rpo, d); - if(d > COSTHI) - d = COSTHI; - s->damage = d; - heapadd(s); -} - -static Reg* -findjump(BB *b) -{ - Reg *r, *l; - - r = b->first; - l = b->last; - - for(;;) { - if(r->prog->as == AJMP) - break; - if(r == l) { - diag(Z, "findjump botch"); - break; - } - r = r->link; - } - return r; -} - -static BB* -findset(int r) -{ - BB *s, **p; - int n, n2; - - if(r < ordered[0]->first->rpo) - return nil; - n = bcount; - p = ordered; - while(n > 0) { - n2 = n >> 1; - s = p[n2]; - if(r < s->first->rpo) { - n = n2; - continue; - } - if(r > s->last->rpo) { - n2++; - p += n2; - n -= n2; - continue; - } - return s; - } - diag(Z, "findset botch"); - return nil; -} - -static void -wound(Reg *r) -{ - BB *b, *p, **n; - BBset *s; - - b = findset(r->rpo); - if(b == nil) - return; - s = b->set; - if(s == nil) - return; - for(n = &s->ents; (p = *n) != nil; n = &(*n)->link) { - if(p == b) { - *n = b->link; - b->link = wounded; - wounded = b; - bbsrecalc(s); - return; - } - } -} - -static void -printbl(Reg *l) -{ - if(l == nil) { - print("Z"); - return; - } - - print("%ld", l->rpo); - while((l = l->p2link) != nil) - print(" %ld", l->rpo); -} - -static void -appset(Reg *e, Reg *s) -{ - for(;;) { - if(s->p2link == R) { - s->p2link = e; - return; - } - s = s->p2link; - } -} - -static Reg* -delset(Reg *e, Reg *s) -{ - Reg *c, *l; - - c = s; - l = nil; - for(;;) { - if(e == c) { - if(l == nil) - return s->p2link; - l->p2link = c->p2link; - return s; - } - l = c; - c = c->p2link; - if(c == nil) - return s; - } -} - -static void -redest(Reg *s, Reg *d) -{ - while(s != R) { - s->s2 = d; - s = s->p2link; - } -} - -static void -changedest(Reg *s, Reg *d, int x) -{ - Reg *l; - - if(bdebug) { - print("change %ld [", s->rpo); - printbl(s->p2); - print("] -> %ld [", d->rpo); - printbl(d->p2); - print("]\n"); - } - - if(s->p2 == nil) { -// print("deadjmp\n"); - return; - } - - l = s->p2; - for(;;) { - if(bdebug) - print("s2 %ld = %ld\n", l->rpo, d->rpo); - l->s2 = d; - wound(l); - if(l->p2link == nil) - break; - l = l->p2link; - } - - if(x) { - l->p2link = delset(s, d->p2); - d->p2 = s->p2; - } - else { - l->p2link = d->p2; - d->p2 = s->p2; - s->p2 = nil; - } - - if(bdebug) { - print("result ["); - printbl(d->p2); - print("]\n"); - } - - bchange = 1; -} - -static void -bexcise(BB *b) -{ - Reg *r, *l; - - l = b->last; - r = b->first; - if(bdebug) - print("excise %ld to %ld\n", r->rpo, l->rpo); - for(;;) { - r->prog->as = ANOP; - r->prog->to.type = D_NONE; - r->p2 = R; - if(r->s2 != R) { - r->s2->p2 = delset(r, r->s2->p2); - r->s2 = R; - } - if(r == l) - break; - r = r->link; - } -} - -static int -backtrack(Reg *s, Reg *d) -{ - int i; - char l[BINST], r[BINST]; - -//print("backtrack %ld %ld\n", Rn(s), Rn(d)); - i = 0; - while(s != nil && d != nil) { - if(snprint(l, BINST, "%P", s->prog) == BINST) - break; - if(snprint(r, BINST, "%P", d->prog) == BINST) - break; -//print("%s\t%s\n", l, r); - if(strcmp(l, r) != 0) - break; - i++; - s = s->p2link; - d = d->p2link; - } - return i; -} - -static void -checktails(void) -{ - int c; - Reg *r; - - c = 0; - for(r = firstr; r->link != R; r = r->link) { - if(r->prog->as == AJMP && r->s2 != nil) - c += backtrack(r->p1, r->s2->p1); - } - - if(c > 0) - print("tails %s %d\n", firstr->prog->from.sym->name, c); -} - -static void -process(BBset *s) -{ - Reg *h; - BB *f, *o, *p, *t; - - if(bdebug) - print("process %d %x %x\n", s->damage, s->hash[0], s->hash[1]); - f = s->ents; - if(f->flags & Bjo) { - s->ents = nil; - h = findjump(f)->s2; - o = nil; - while(f != nil) { - t = f->link; - if((f->flags & Bjo) != 0 && f->first->s2 != f->first) { - changedest(f->first, h, 1); - bexcise(f); - } - else { - f->link = o; - o = f; - } - f = t; - } - s->ents = o; - } - else { - o = nil; - p = nil; - while(f != nil) { - t = f->link; - if((f->flags & (Bpre|Bpin)) != 0 || (f->last->link == R)) { - f->link = p; - p = f; - } - else { - f->link = o; - o = f; - } - f = t; - } - if(o == nil) { - diag(Z, "all Bpre"); - return; - } - if(p == nil) { - p = o; - o = p->link; - p->link = nil; - s->ents = p; - } - else - s->ents = p; - - h = p->first; - // oblit o list repl with jmp to h - while(o != nil) { - changedest(o->first, h, 1); - bexcise(o); - o = o->link; - } - - bbsrecalc(s); - } -} - -static void -iterate(void) -{ - BBset *s; - BB *b, *t; - - heapn = 0; - - for(;;) { - for(b = wounded; b != nil; b = t) { - t = b->link; - enterbb(b); - } - wounded = nil; - - for(s = recalc; s != nil; s = s->link) - calcdamage(s); - recalc = nil; - - if(heapn == 0) - return; - - s = heap[1]; - heapremove(s); - process(s); - } -} - -static void -cleanup(void) -{ - int i; - BB *l, *n; - BBset *b, *t; - - for(i = 0; i < BBHASH; i++) { - b = bbhash[i]; - bbhash[i] = nil; - while(b != nil) { - t = b->next; - bsfree(b); - b = t; - } - } - for(i = 0; i < bcount; i++) - bfree(ordered[i]); - for(l = bbaux; l != nil; l = n) { - n = l->aux; - bfree(l); - } - bbaux = nil; -} - -static void -prreg(Reg *r) -{ - Prog *p; - - p = r->prog; - if(p->to.type == D_BRANCH) - p->to.offset = r->s2->rpo; - print("%ld:%P\tr %lX ", r->rpo, r->prog, r->regu); - print("p1 %ld p2 %ld p2l %ld s1 %ld s2 %ld link %ld", - Rn(r->p1), Rn(r->p2), Rn(r->p2link), - Rn(r->s1), Rn(r->s2), Rn(r->link)); - if(!r->active) - print(" d"); -// print(" %p %p\n", r->prog, r->prog->link); - print("\n"); -} - -static void prfunc(char*); - -static void -checkr(int d) -{ - Prog *p; - Reg *r, *t; - - for(r = firstr; r->link != R; r = r->link) { - for(p = r->prog->link; p != P && p != r->link->prog; p = p->link) - ; - if(p == P) { - print("%ld: bad prog link\n", r->rpo); - if(d) - prfunc(nil); - abort(); - } - if(r->s1 != R && (r->s1 != r->link || r->link->p1 != r)) { - print("%ld: bad s1 p1\n", r->rpo); - if(d) - prfunc(nil); - abort(); - } - if(r->s2 != R && r->s2->p2 == nil) { - print("%ld: no p2 for s2\n", r->rpo); - if(d) - prfunc(nil); - abort(); - } - if(r->p2 != R) { - t = r->p2->s2; - while(t != r) { - t = t->p2link; - if(t == R) { - print("%ld: bad s2 for p2\n", r->rpo); - if(d) - prfunc(nil); - abort(); - } - } - } - } -} - -static void -prfunc(char *s) -{ - Reg *r; - - if(s != nil) - print("%s structure %s\n", s, firstr->prog->from.sym->name); - for(r = firstr; r != R; r = r->link) - prreg(r); - if(s != nil) { - print("end\n"); - checkr(0); - } -} - -/* find p in r's list and replace with l */ -static void -adjprog(Reg *r, Prog *p, Prog *l) -{ - Prog *t, **n; - - for(n = &r->prog->link; (t = *n) != nil; n = &t->link) { - if(t == p) { - *n = l; - return; - } - } - print("adjprog botch\n"); - abort(); -} - -static void -jumptojump(void) -{ - Reg *r; - - for(r = firstr; r != R; r = r->link) { - if(r->prog->as == AJMP && r->p2 != R && r->s2 != r) { - if(bdebug) - print("jump as dest %ld -> %ld\n", r->rpo, r->s2->rpo); - changedest(r, r->s2, 0); - bchange++; - } - } -} - -/* drag a tail to replace a jump. seems to be a bad idea. */ -static void -rearrange(void) -{ - int i; - Reg *j, *t; - BB *b, *p, *s; - - for(i = 0; i < bcount; i++) { - b = ordered[i]; - if(b->flags & Bdel) - continue; - j = b->last; - if(j->prog->as == AJMP && j->s2->p1 == R) { - t = j->s2; - if(t == b->first) - continue; - s = findset(t->rpo); - if(s == nil) { - diag(Z, "no self"); - continue; - } - if(s == ordered[0]) - continue; - if(s->flags & Bdel) - continue; - if(s->last->link == R) - continue; - if(bdebug) - print("drag %ld to %ld\n", t->rpo, j->rpo); - p = findset(t->rpo - 1); - if(p == nil) { - diag(Z, "no predec"); - continue; - } - if(p->last->link != t) { - diag(Z, "bad predec %ld %ld", p->last->rpo, t->rpo); - continue; - } - - /* poison everything in sight */ - b->flags |= Bdel; - s->flags |= Bdel; - findset(j->link->rpo)->flags |= Bdel; - findset(s->last->link->rpo)->flags |= Bdel; - - /* remove */ - adjprog(p->last, t->prog, s->last->link->prog); - p->last->link = s->last->link; - - /* fix tail */ - adjprog(s->last, s->last->link->prog, j->link->prog); - s->last->link = j->link; - - /* fix head */ - adjprog(j, j->link->prog, t->prog); - j->link = t; - - /* nop the jump */ - j->prog->as = ANOP; - j->prog->to.type = D_NONE; - j->s2 = nil; - j->link->p2 = delset(j, j->link->p2); - j->s1 = t; - t->p1 = j; - if(bcheck) - checkr(1); - bchange++; - } - } -} - -void -jumptodot(void) -{ - Reg *r; - - for(r = firstr; r != R; r = r->link) { - if(r->prog->as == AJMP && r->s2 == r->link) { - if(debug['v']) - print("jump to next %ld\n", r->rpo); - r->prog->as = ANOP; - r->prog->to.type = D_NONE; - r->s2 = nil; - r->link->p2 = delset(r, r->link->p2); - findset(r->rpo)->flags |= Bdel; - findset(r->link->rpo)->flags |= Bdel; - bchange++; - } - } -} - -void -comtarg(void) -{ - int n; - BB *b, *c; - Reg *r, *l, *p, *t; - -loop: - bchange = 0; - - /* excise NOPS because they just get in the way */ - /* some have p2 because they are excised labelled moves */ - - if(debug['v']) { - n = 0; - for(r = firstr; r != R; r = r->link) - r->rpo = n++; - prfunc("prenop"); - } - - r = firstr; - l = r->link; - while(l != R) { - if(l->prog->as == ANOP) { - t = l->p1; - p = l->p2; -if(dbg) print("nop %ld [", l->rpo); -if(dbg) printbl(p); - for(;;) { - adjprog(r, l->prog, l->prog->link); - r->link = l->link; - l->link = freer; - freer = l; - l = r->link; - if(l->prog->as != ANOP) - break; -if(dbg) print("] %ld [", l->rpo); -if(dbg) printbl(l->p2); - if(p == R) - p = l->p2; - else if(l->p2 != nil) - appset(l->p2, p); - } -if(dbg) print("] %ld [", l->rpo); -if(dbg) printbl(l->p2); - if(p != R) { - redest(p, l); - if(l->p2 != R) - appset(p, l->p2); - else - l->p2 = p; - } -if(dbg) print("] -> ["); -if(dbg) printbl(l->p2); -if(dbg) print("]\n"); - if(r->s1 != R) - r->s1 = l; - l->p1 = t; - } - r = l; - l = r->link; - } - - n = 0; - for(r = firstr; r != R; r = r->link) - r->rpo = n++; - - if(debug['v']) - prfunc("input"); - - firstbb = nil; - lastbb = nil; - - if(debug['v']) - print("bbstart\n"); - - n = 0; - r = firstr; - do { - b = bba(); - b->first = r; - for(;;) { - l = r; - r = r->link; - switch(l->prog->as) { - case ARET: - case AJMP: - case AIRETL: - goto out; - } - if(r->p2 != R) - break; - } - out: - b->last = l; - if(lastbb == nil) - firstbb = b; - else - lastbb->link = b; - lastbb = b; - if(bdebug) - print("BB %ld %ld\n", b->first->rpo, b->last->rpo); - n++; - } while(r != R); - - if(debug['v']) - print("end\n"); - - if(n > bsize) { - bsize = n * 3 / 2; - if(bsize < BBINIT) - bsize = BBINIT; - ordered = alloc(bsize * sizeof(*ordered)); - heap = alloc((bsize + 1) * sizeof(*ordered)); - } - - if(debug['v']) - print("preprocstart\n"); - - n = 0; - for(b = firstbb; b != nil; b = c) { - c = b->link; - preproc(b, n++); - } - - if(debug['v']) - print("end\n"); - - bcount = n; - - jumptojump(); - - if(debug['v']) - print("iteratestart\n"); - - iterate(); -//checktails(); - - if(debug['v']) - print("end\n"); - - if(debug['v']) - print("extrastart\n"); - - jumptodot(); -// rearrange(); - - if(debug['v']) - print("end\n"); - - cleanup(); - if(bballoc || bbsalloc) - diag(Z, "bballoc %d %d", bballoc, bbsalloc); - - if(debug['v']) - prfunc("output"); - - if(1 && bchange) - goto loop; -} diff -r d8d00747375b sys/src/cmd/8c/bound.h --- a/sys/src/cmd/8c/bound.h Thu Sep 29 03:00:00 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * Bounding Box stuff (brucee 04/03/30). - */ - -#include -#include - -typedef struct BB BB; -typedef struct BBset BBset; -typedef uchar Hval[SHA1dlen]; - -#define BBEQ(a, b) (memcmp((a), (b), SHA1dlen) == 0) -#define BBMKHASH(b, n, h) sha1((uchar *)(b), (n), (h), nil) -#define BBCP(d, s) memmove(d, s, SHA1dlen) - -enum -{ - Bpre = 1 << 0, /* has a flow in */ - Bjo = 1 << 1, /* a jump only */ - Bbig = 1 << 2, /* too big */ - Bdel = 1 << 3, /* deleted or not of interest */ - Bpin = 1 << 4, /* pinned by embedded labels */ - - BBHASH = 64, /* power of 2 <= 256 */ - BBMASK = BBHASH - 1, - - BBINIT = 128, - BBBIG = 64, - BBBSIZE = 8192, - BINST = 128, - - COSTHI = 0x7F, - COSTJO = 0xFF, -}; - -struct BB -{ - Reg* first; - Reg* last; - BBset* set; - BB* link; - BB* aux; - short flags; - short len; -}; - -struct BBset -{ - Hval hash; - BB* ents; - BBset* next; - BBset* link; - short index; - uchar damage; - uchar recalc; -}; diff -r d8d00747375b sys/src/cmd/8c/cgen.c --- a/sys/src/cmd/8c/cgen.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/8c/cgen.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,3 +1,33 @@ +// Inferno utils/8c/cgen.c +// http://code.google.com/p/inferno-os/source/browse/utils/8c/cgen.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 "gc.h" /* ,x/^(print|prtree)\(/i/\/\/ */ @@ -9,7 +39,7 @@ Prog *p1; Node nod, nod1, nod2, nod3, nod4; int o, hardleft; - long v, curs; + int32 v, curs; vlong c; if(debug['g']) { @@ -25,6 +55,12 @@ l = n->left; r = n->right; o = n->op; + + if(n->op == OEXREG || (nn != Z && nn->op == OEXREG)) { + gmove(n, nn); + return; + } + if(n->addable >= INDEXED) { if(nn == Z) { switch(o) { @@ -316,7 +352,7 @@ c = r->vconst; if(c < 0) c = -c; - v = log2(c); + v = xlog2(c); if(v < 0) break; /* fall thru */ @@ -361,27 +397,20 @@ t = l; l = r; r = t; - goto imula; } - else if(r->addable >= INDEXED) { - imula: -/* should favour AX */ - regalloc(&nod, l, nn); - cgen(l, &nod); - gopcode(OMUL, n->type, r, &nod); - } - else { -/* should favour AX */ - regalloc(&nod, l, nn); - cgen(l, &nod); + /* should favour AX */ + regalloc(&nod, l, nn); + cgen(l, &nod); + if(r->addable < INDEXED) { regalloc(&nod1, r, Z); cgen(r, &nod1); gopcode(OMUL, n->type, &nod1, &nod); regfree(&nod1); - } + }else + gopcode(OMUL, n->type, r, &nod); /* addressible */ gmove(&nod, nn); regfree(&nod); - goto done; + break; } /* @@ -434,33 +463,21 @@ } reg[D_AX]++; - if(r->op == OCONST) { - switch(o) { - case ODIV: - reg[D_DX]++; - if(l->addable < INDEXED) { - regalloc(&nod2, l, Z); - cgen(l, &nod2); - l = &nod2; - } + if(r->op == OCONST && (o == ODIV || o == OLDIV)) { + reg[D_DX]++; + if(l->addable < INDEXED) { + regalloc(&nod2, l, Z); + cgen(l, &nod2); + l = &nod2; + } + if(o == ODIV) sdivgen(l, r, &nod, &nod1); - gmove(&nod1, nn); - if(l == &nod2) - regfree(l); - goto freeaxdx; - case OLDIV: - reg[D_DX]++; - if(l->addable < INDEXED) { - regalloc(&nod2, l, Z); - cgen(l, &nod2); - l = &nod2; - } + else udivgen(l, r, &nod, &nod1); - gmove(&nod1, nn); - if(l == &nod2) - regfree(l); - goto freeaxdx; - } + gmove(&nod1, nn); + if(l == &nod2) + regfree(l); + goto freeaxdx; } if(l->complex >= r->complex) { @@ -598,7 +615,7 @@ c = r->vconst; if(c < 0) c = -c; - v = log2(c); + v = xlog2(c); if(v < 0) break; /* fall thru */ @@ -650,7 +667,7 @@ } if(o == OASMUL) { -/* should favour AX */ + /* should favour AX */ regalloc(&nod, l, nn); if(r->complex >= FNX) { regalloc(&nod1, r, Z); @@ -680,7 +697,7 @@ regfree(&nod); if(hardleft) regfree(&nod2); - goto done; + break; } /* @@ -914,7 +931,7 @@ regfree(&nod); } else gopcode(OFUNC, n->type, Z, l); - if(REGARG>=0 && reg[REGARG]) + if(REGARG >= 0 && reg[REGARG]) reg[REGARG]--; if(nn != Z) { regret(&nod, n); @@ -1020,7 +1037,7 @@ diag(n, "DOT and no offset"); break; } - nod.xoffset += (long)r->vconst; + nod.xoffset += (int32)r->vconst; nod.type = n->type; cgen(&nod, nn); break; @@ -1122,7 +1139,7 @@ reglcgen(Node *t, Node *n, Node *nn) { Node *r; - long v; + int32 v; regialloc(t, n, nn); if(n->op == OIND) { @@ -1206,7 +1223,7 @@ int o; Prog *p1, *p2; Node *l, *r, nod, nod1; - long curs; + int32 curs; if(debug['g']) { prtree(nn, "boolgen lhs"); @@ -1418,7 +1435,7 @@ } void -sugen(Node *n, Node *nn, long w) +sugen(Node *n, Node *nn, int32 w) { Prog *p1; Node nod0, nod1, nod2, nod3, nod4, *h, *l, *r; @@ -1489,7 +1506,7 @@ diag(n, "DOT and no offset"); break; } - nod1.xoffset += (long)r->vconst; + nod1.xoffset += (int32)r->vconst; nod1.type = n->type; sugen(&nod1, nn, w); break; @@ -1564,7 +1581,7 @@ nod0.addable = 0; nod0.right = l; - /* prtree(&nod0, "hand craft"); /* */ + // prtree(&nod0, "hand craft"); cgen(&nod0, Z); } break; @@ -1636,6 +1653,7 @@ case OASMUL: case OASLMUL: + case OASASHL: case OASASHR: case OASLSHR: diff -r d8d00747375b sys/src/cmd/8c/cgen64.c --- a/sys/src/cmd/8c/cgen64.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/8c/cgen64.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,3 +1,33 @@ +// Inferno utils/8c/cgen64.c +// http://code.google.com/p/inferno-os/source/browse/utils/8c/cgen64.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 "gc.h" void @@ -24,22 +54,22 @@ return 0; } -long +int32 hi64v(Node *n) { - if(align(0, types[TCHAR], Aarg1)) /* isbigendian */ - return (long)(n->vconst) & ~0L; + if(align(0, types[TCHAR], Aarg1, nil)) /* isbigendian */ + return (int32)(n->vconst) & ~0L; else - return (long)((uvlong)n->vconst>>32) & ~0L; + return (int32)((uvlong)n->vconst>>32) & ~0L; } -long +int32 lo64v(Node *n) { - if(align(0, types[TCHAR], Aarg1)) /* isbigendian */ - return (long)((uvlong)n->vconst>>32) & ~0L; + if(align(0, types[TCHAR], Aarg1, nil)) /* isbigendian */ + return (int32)((uvlong)n->vconst>>32) & ~0L; else - return (long)(n->vconst) & ~0L; + return (int32)(n->vconst) & ~0L; } Node * @@ -188,70 +218,6 @@ freepair(n); } -/* generate a cast t from n to tt */ -static void -cast(Node *n, Type *t, Node *nn) -{ - Node *r; - - r = new(OCAST, n, Z); - r->type = t; - sugen(r, nn, 8); -} - -static void -swapregs(Node *a, Node *b) -{ - int t; - - t = a->reg; - a->reg = b->reg; - b->reg = t; -} - -static void -swappairs(Node *a, Node *b) -{ - swapregs(a->left, b->left); - swapregs(a->right, b->right); -} - -static int -saveme(Node *n) -{ - int r; - - r = n->reg; - return r >= D_AX && r <= D_DI; -} - -static void -saveit(Node *n, Node *t, Node *r) -{ - Node nod; - - if(saveme(n)) { - t->reg = n->reg; - gins(AMOVL, t, r); - r->xoffset += SZ_LONG; - if(n->reg == D_AX) { - regalloc(&nod, n, Z); - regfree(n); - n->reg = nod.reg; - } - } -} - -static void -restoreit(Node *n, Node *t, Node *r) -{ - if(saveme(n)) { - t->reg = n->reg; - gins(AMOVL, r, t); - r->xoffset += SZ_LONG; - } -} - enum { /* 4 only, see WW */ @@ -319,26 +285,6 @@ return t; } -static int -forcereg(Node *d, int r, int o, Node *t) -{ - int a; - - if(d->reg != D_NONE) - diag(Z, "force alloc"); - d->reg = r; - a = 0; - if(reg[r]) { - reg[o]++; - regalloc(t, d, Z); - a = 1; - gins(AMOVL, d, t); - reg[o]--; - } - reg[r]++; - return a; -} - /* try to steal a reg */ static int getreg(Node **np, Node *t, int r) @@ -2681,19 +2627,7 @@ testv(Node *n, int true) { Type *t; - Node *nn, nod, *b; - - if(machcap(Z)) { - b = &nod; - b->op = true ? ONE : OEQ; - b->left = n; - b->right = new(0, Z, Z); - *b->right = *nodconst(0); - b->right->type = n->type; - b->type = types[TLONG]; - cgen64(b, Z); - return; - } + Node *nn, nod; switch(n->op) { case OINDREG: diff -r d8d00747375b sys/src/cmd/8c/div.c --- a/sys/src/cmd/8c/div.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/8c/div.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,3 +1,33 @@ +// Inferno utils/8c/div.c +// http://code.google.com/p/inferno-os/source/browse/utils/8c/div.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 "gc.h" /* @@ -6,12 +36,12 @@ * SIGPLAN Notices, Vol. 29, June 1994, page 61. */ -#define TN(n) (1ULL << (n)) +#define TN(n) ((uvlong)1 << (n)) #define T31 TN(31) #define T32 TN(32) int -multiplier(ulong d, int p, uvlong *mp) +multiplier(uint32 d, int p, uvlong *mp) { int l; uvlong mlo, mhi, tlo, thi; @@ -22,7 +52,7 @@ mhi = (((TN(l) + 1 - d) << 32) / d) + T32; else mhi = (TN(32 + l) + TN(32 + l - p)) / d; - assert(mlo < mhi); + /*assert(mlo < mhi);*/ while(l > 0) { tlo = mlo >> 1; thi = mhi >> 1; @@ -37,7 +67,7 @@ } int -sdiv(ulong d, ulong *mp, int *sp) +sdiv(uint32 d, uint32 *mp, int *sp) { int s; uvlong m; @@ -52,7 +82,7 @@ } int -udiv(ulong d, ulong *mp, int *sp, int *pp) +udiv(uint32 d, uint32 *mp, int *sp, int *pp) { int p, s; uvlong m; @@ -69,7 +99,7 @@ *mp = m; *pp = p; if(m >= T32) { - assert(p == 0); + /*assert(p == 0);*/ *sp = s - 1; return 1; } @@ -83,14 +113,14 @@ sdivgen(Node *l, Node *r, Node *ax, Node *dx) { int a, s; - ulong m; + uint32 m; vlong c; c = r->vconst; if(c < 0) c = -c; a = sdiv(c, &m, &s); -//print("a=%d i=%ld s=%d m=%lux\n", a, (long)r->vconst, s, m); +//print("a=%d i=%d s=%d m=%ux\n", a, (int32)r->vconst, s, m); gins(AMOVL, nodconst(m), ax); gins(AIMULL, l, Z); gins(AMOVL, l, ax); @@ -107,11 +137,11 @@ udivgen(Node *l, Node *r, Node *ax, Node *dx) { int a, s, t; - ulong m; + uint32 m; Node nod; a = udiv(r->vconst, &m, &s, &t); -//print("a=%ud i=%ld p=%d s=%d m=%lux\n", a, (long)r->vconst, t, s, m); +//print("a=%ud i=%d p=%d s=%d m=%ux\n", a, (int32)r->vconst, t, s, m); if(t != 0) { gins(AMOVL, l, ax); gins(ASHRL, nodconst(t), ax); @@ -154,7 +184,7 @@ } void -sdiv2(long c, int v, Node *l, Node *n) +sdiv2(int32 c, int v, Node *l, Node *n) { Node nod; @@ -176,7 +206,7 @@ } void -smod2(long c, int v, Node *l, Node *n) +smod2(int32 c, int v, Node *l, Node *n) { Node nod; diff -r d8d00747375b sys/src/cmd/8c/enam.c --- a/sys/src/cmd/8c/enam.c Thu Sep 29 03:00:00 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,337 +0,0 @@ -char* anames[] = -{ - "XXX", - "AAA", - "AAD", - "AAM", - "AAS", - "ADCB", - "ADCL", - "ADCW", - "ADDB", - "ADDL", - "ADDW", - "ADJSP", - "ANDB", - "ANDL", - "ANDW", - "ARPL", - "BOUNDL", - "BOUNDW", - "BSFL", - "BSFW", - "BSRL", - "BSRW", - "BTL", - "BTW", - "BTCL", - "BTCW", - "BTRL", - "BTRW", - "BTSL", - "BTSW", - "BYTE", - "CALL", - "CLC", - "CLD", - "CLI", - "CLTS", - "CMC", - "CMPB", - "CMPL", - "CMPW", - "CMPSB", - "CMPSL", - "CMPSW", - "DAA", - "DAS", - "DATA", - "DECB", - "DECL", - "DECW", - "DIVB", - "DIVL", - "DIVW", - "ENTER", - "GLOBL", - "GOK", - "HISTORY", - "HLT", - "IDIVB", - "IDIVL", - "IDIVW", - "IMULB", - "IMULL", - "IMULW", - "INB", - "INL", - "INW", - "INCB", - "INCL", - "INCW", - "INSB", - "INSL", - "INSW", - "INT", - "INTO", - "IRETL", - "IRETW", - "JCC", - "JCS", - "JCXZ", - "JEQ", - "JGE", - "JGT", - "JHI", - "JLE", - "JLS", - "JLT", - "JMI", - "JMP", - "JNE", - "JOC", - "JOS", - "JPC", - "JPL", - "JPS", - "LAHF", - "LARL", - "LARW", - "LEAL", - "LEAW", - "LEAVEL", - "LEAVEW", - "LOCK", - "LODSB", - "LODSL", - "LODSW", - "LONG", - "LOOP", - "LOOPEQ", - "LOOPNE", - "LSLL", - "LSLW", - "MOVB", - "MOVL", - "MOVW", - "MOVBLSX", - "MOVBLZX", - "MOVBWSX", - "MOVBWZX", - "MOVWLSX", - "MOVWLZX", - "MOVSB", - "MOVSL", - "MOVSW", - "MULB", - "MULL", - "MULW", - "NAME", - "NEGB", - "NEGL", - "NEGW", - "NOP", - "NOTB", - "NOTL", - "NOTW", - "ORB", - "ORL", - "ORW", - "OUTB", - "OUTL", - "OUTW", - "OUTSB", - "OUTSL", - "OUTSW", - "POPAL", - "POPAW", - "POPFL", - "POPFW", - "POPL", - "POPW", - "PUSHAL", - "PUSHAW", - "PUSHFL", - "PUSHFW", - "PUSHL", - "PUSHW", - "RCLB", - "RCLL", - "RCLW", - "RCRB", - "RCRL", - "RCRW", - "REP", - "REPN", - "RET", - "ROLB", - "ROLL", - "ROLW", - "RORB", - "RORL", - "RORW", - "SAHF", - "SALB", - "SALL", - "SALW", - "SARB", - "SARL", - "SARW", - "SBBB", - "SBBL", - "SBBW", - "SCASB", - "SCASL", - "SCASW", - "SETCC", - "SETCS", - "SETEQ", - "SETGE", - "SETGT", - "SETHI", - "SETLE", - "SETLS", - "SETLT", - "SETMI", - "SETNE", - "SETOC", - "SETOS", - "SETPC", - "SETPL", - "SETPS", - "CDQ", - "CWD", - "SHLB", - "SHLL", - "SHLW", - "SHRB", - "SHRL", - "SHRW", - "STC", - "STD", - "STI", - "STOSB", - "STOSL", - "STOSW", - "SUBB", - "SUBL", - "SUBW", - "SYSCALL", - "TESTB", - "TESTL", - "TESTW", - "TEXT", - "VERR", - "VERW", - "WAIT", - "WORD", - "XCHGB", - "XCHGL", - "XCHGW", - "XLAT", - "XORB", - "XORL", - "XORW", - "FMOVB", - "FMOVBP", - "FMOVD", - "FMOVDP", - "FMOVF", - "FMOVFP", - "FMOVL", - "FMOVLP", - "FMOVV", - "FMOVVP", - "FMOVW", - "FMOVWP", - "FMOVX", - "FMOVXP", - "FCOMB", - "FCOMBP", - "FCOMD", - "FCOMDP", - "FCOMDPP", - "FCOMF", - "FCOMFP", - "FCOML", - "FCOMLP", - "FCOMW", - "FCOMWP", - "FUCOM", - "FUCOMP", - "FUCOMPP", - "FADDDP", - "FADDW", - "FADDL", - "FADDF", - "FADDD", - "FMULDP", - "FMULW", - "FMULL", - "FMULF", - "FMULD", - "FSUBDP", - "FSUBW", - "FSUBL", - "FSUBF", - "FSUBD", - "FSUBRDP", - "FSUBRW", - "FSUBRL", - "FSUBRF", - "FSUBRD", - "FDIVDP", - "FDIVW", - "FDIVL", - "FDIVF", - "FDIVD", - "FDIVRDP", - "FDIVRW", - "FDIVRL", - "FDIVRF", - "FDIVRD", - "FXCHD", - "FFREE", - "FLDCW", - "FLDENV", - "FRSTOR", - "FSAVE", - "FSTCW", - "FSTENV", - "FSTSW", - "F2XM1", - "FABS", - "FCHS", - "FCLEX", - "FCOS", - "FDECSTP", - "FINCSTP", - "FINIT", - "FLD1", - "FLDL2E", - "FLDL2T", - "FLDLG2", - "FLDLN2", - "FLDPI", - "FLDZ", - "FNOP", - "FPATAN", - "FPREM", - "FPREM1", - "FPTAN", - "FRNDINT", - "FSCALE", - "FSIN", - "FSINCOS", - "FSQRT", - "FTST", - "FXAM", - "FXTRACT", - "FYL2X", - "FYL2XP1", - "END", - "DYNT", - "INIT", - "SIGNAME", - "LAST", -}; diff -r d8d00747375b sys/src/cmd/8c/gc.h --- a/sys/src/cmd/8c/gc.h Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/8c/gc.h Mon Nov 14 17:35:25 2011 +0100 @@ -1,5 +1,36 @@ +// Inferno utils/8c/gc.h +// http://code.google.com/p/inferno-os/source/browse/utils/8c/gc.h +// +// 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 #include "../cc/cc.h" -#include "../8c/8.out.h" +#include "../8l/8.out.h" /* * 8c/386 @@ -35,7 +66,8 @@ struct Adr { - long offset; + int32 offset; + int32 offset2; double dval; char sval[NSNAME]; @@ -53,7 +85,7 @@ Adr from; Adr to; Prog* link; - long lineno; + int32 lineno; short as; }; #define P ((Prog*)0) @@ -61,22 +93,22 @@ struct Case { Case* link; - long val; - long label; + int32 val; + int32 label; char def; - char isv; + char isv; }; #define C ((Case*)0) struct C1 { - long val; - long label; + int32 val; + int32 label; }; struct Var { - long offset; + int32 offset; Sym* sym; char name; char etype; @@ -84,8 +116,8 @@ struct Reg { - long pc; - long rpo; /* reverse post ordering */ + int32 pc; + int32 rpo; /* reverse post ordering */ Bits set; Bits use1; @@ -98,11 +130,11 @@ Bits regdiff; Bits act; - long regu; - long loop; /* could be shorter */ + int32 regu; + int32 loop; /* could be shorter */ Reg* log5; - long active; + int32 active; Reg* p1; Reg* p2; @@ -131,25 +163,26 @@ short regno; }; -EXTERN long breakpc; -EXTERN long nbreak; +EXTERN int32 breakpc; +EXTERN int32 nbreak; EXTERN Case* cases; EXTERN Node constnode; EXTERN Node fconstnode; -EXTERN long continpc; -EXTERN long curarg; -EXTERN long cursafe; +EXTERN int32 continpc; +EXTERN int32 curarg; +EXTERN int32 cursafe; EXTERN Prog* firstp; EXTERN Prog* lastp; -EXTERN long maxargsafe; +EXTERN int32 maxargsafe; EXTERN int mnstring; +EXTERN int retok; EXTERN Node* nodrat; EXTERN Node* nodret; EXTERN Node* nodsafe; -EXTERN long nrathole; -EXTERN long nstring; +EXTERN int32 nrathole; +EXTERN int32 nstring; EXTERN Prog* p; -EXTERN long pc; +EXTERN int32 pc; EXTERN Node regnode; EXTERN Node fregnode0; EXTERN Node fregnode1; @@ -158,8 +191,8 @@ EXTERN Node znode; EXTERN Prog zprog; EXTERN int reg[D_NONE]; -EXTERN long exregoffset; -EXTERN long exfregoffset; +EXTERN int32 exregoffset; +EXTERN int32 exfregoffset; #define BLOAD(r) band(bnot(r->refbehind), r->refahead) #define BSTORE(r) band(bnot(r->calbehind), r->calahead) @@ -183,8 +216,8 @@ EXTERN Bits consts; EXTERN Bits addrs; -EXTERN long regbits; -EXTERN long exregbits; +EXTERN int32 regbits; +EXTERN int32 exregbits; EXTERN int change; EXTERN int suppress; @@ -194,9 +227,9 @@ EXTERN Reg zreg; EXTERN Reg* freer; EXTERN Var var[NVAR]; -EXTERN long* idom; +EXTERN int32* idom; EXTERN Reg** rpo2r; -EXTERN long maxnr; +EXTERN int32 maxnr; extern char* anames[]; @@ -210,6 +243,8 @@ void xcom(Node*); void indx(Node*); int bcomplex(Node*, Node*); +Prog* gtext(Sym*, int32); +vlong argsize(void); /* * cgen.c @@ -220,7 +255,7 @@ void lcgen(Node*, Node*); void bcgen(Node*, int); void boolgen(Node*, int, Node*); -void sugen(Node*, Node*, long); +void sugen(Node*, Node*, int32); int needreg(Node*, int); /* @@ -239,7 +274,7 @@ void nextpc(void); void gargs(Node*, Node*, Node*); void garg1(Node*, Node*, Node*, int, Node**); -Node* nodconst(long); +Node* nodconst(int32); Node* nodfconst(double); int nodreg(Node*, Node*, int); int isreg(Node*, int); @@ -259,7 +294,7 @@ void gopcode(int, Type*, Node*, Node*); int samaddr(Node*, Node*); void gbranch(int); -void patch(Prog*, long); +void patch(Prog*, int32); int sconst(Node*); void gpseudo(int, Sym*, Node*); @@ -268,14 +303,14 @@ */ int swcmp(const void*, const void*); void doswit(Node*); -void swit1(C1*, int, long, Node*); -void casf(void); +void swit1(C1*, int, int32, Node*); +void newcase(void); void bitload(Node*, Node*, Node*, Node*, Node*); void bitstore(Node*, Node*, Node*, Node*, Node*); -long outstring(char*, long); +int32 outstring(char*, int32); void nullwarn(Node*, Node*); -void sextern(Sym*, Node*, long, long); -void gextern(Sym*, Node*, long, long); +void sextern(Sym*, Node*, int32, int32); +void gextern(Sym*, Node*, int32, int32); void outcode(void); void ieeedtod(Ieee*, double); @@ -300,12 +335,12 @@ void addmove(Reg*, int, int, int); Bits mkvar(Reg*, Adr*); void prop(Reg*, Bits, Bits); -void loopit(Reg*, long); +void loopit(Reg*, int32); void synch(Reg*, Bits); -ulong allreg(ulong, Rgn*); +uint32 allreg(uint32, Rgn*); void paint1(Reg*, int); -ulong paint2(Reg*, int); -void paint3(Reg*, int, long, int); +uint32 paint2(Reg*, int); +void paint3(Reg*, int, int32, int); void addreg(Adr*, int); /* @@ -327,10 +362,10 @@ int copysub(Adr*, Adr*, Adr*, int); int copysub1(Prog*, Adr*, Adr*, int); -long RtoB(int); -long FtoB(int); -int BtoR(long); -int BtoF(long); +int32 RtoB(int); +int32 FtoB(int); +int BtoR(int32); +int BtoF(int32); #define D_HI D_NONE #define D_LO D_NONE @@ -347,8 +382,8 @@ int com64(Node*); void com64init(void); void bool64(Node*); -long lo64v(Node*); -long hi64v(Node*); +int32 lo64v(Node*); +int32 hi64v(Node*); Node* lo64(Node*); Node* hi64(Node*); @@ -357,8 +392,8 @@ */ void sdivgen(Node*, Node*, Node*, Node*); void udivgen(Node*, Node*, Node*, Node*); -void sdiv2(long, int, Node*, Node*); -void smod2(long, int, Node*, Node*); +void sdiv2(int32, int, Node*, Node*); +void smod2(int32, int, Node*, Node*); void mulgen(Type*, Node*, Node*); void genmuladd(Node*, Node*, int, Node*); void shiftit(Type*, Node*, Node*); @@ -366,6 +401,7 @@ #pragma varargck type "A" int #pragma varargck type "B" Bits #pragma varargck type "D" Adr* +#pragma varargck type "lD" Adr* #pragma varargck type "P" Prog* #pragma varargck type "R" int #pragma varargck type "S" char* diff -r d8d00747375b sys/src/cmd/8c/list.c --- a/sys/src/cmd/8c/list.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/8c/list.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,3 +1,33 @@ +// Inferno utils/8c/list.c +// http://code.google.com/p/inferno-os/source/browse/utils/8c/list.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. + #define EXTERN #include "gc.h" @@ -27,7 +57,7 @@ if(str[0]) strcat(str, " "); if(var[i].sym == S) { - snprint(ss, sizeof(ss), "$%ld", var[i].offset); + sprint(ss, "$%d", var[i].offset); s = ss; } else s = var[i].sym->name; @@ -46,15 +76,27 @@ Prog *p; p = va_arg(fp->args, Prog*); - if(p->as == ADATA) - snprint(str, sizeof(str), " %A %D/%d,%D", - p->as, &p->from, p->from.scale, &p->to); - else if(p->as == ATEXT) - snprint(str, sizeof(str), " %A %D,%d,%D", - p->as, &p->from, p->from.scale, &p->to); - else - snprint(str, sizeof(str), " %A %D,%D", - p->as, &p->from, &p->to); + switch(p->as) { + case ADATA: + sprint(str, "(%L) %A %D/%d,%D", + p->lineno, p->as, &p->from, p->from.scale, &p->to); + break; + + case ATEXT: + if(p->from.scale) { + sprint(str, "(%L) %A %D,%d,%lD", + p->lineno, p->as, &p->from, p->from.scale, &p->to); + break; + } + sprint(str, "(%L) %A %D,%lD", + p->lineno, p->as, &p->from, &p->to); + break; + + default: + sprint(str, "(%L) %A %D,%lD", + p->lineno, p->as, &p->from, &p->to); + break; + } return fmtstrcpy(fp, str); } @@ -70,7 +112,7 @@ int Dconv(Fmt *fp) { - char str[40], s[20]; + char str[STRINGSZ], s[STRINGSZ]; Adr *a; int i; @@ -78,18 +120,18 @@ i = a->type; if(i >= D_INDIR) { if(a->offset) - snprint(str, sizeof(str), "%ld(%R)", a->offset, i-D_INDIR); + sprint(str, "%d(%R)", a->offset, i-D_INDIR); else - snprint(str, sizeof(str), "(%R)", i-D_INDIR); + sprint(str, "(%R)", i-D_INDIR); goto brk; } switch(i) { default: if(a->offset) - snprint(str, sizeof(str), "$%ld,%R", a->offset, i); + sprint(str, "$%d,%R", a->offset, i); else - snprint(str, sizeof(str), "%R", i); + sprint(str, "%R", i); break; case D_NONE: @@ -97,54 +139,57 @@ break; case D_BRANCH: - snprint(str, sizeof(str), "%ld(PC)", a->offset-pc); + sprint(str, "%d(PC)", a->offset-pc); break; case D_EXTERN: - snprint(str, sizeof(str), "%s+%ld(SB)", a->sym->name, a->offset); + sprint(str, "%s+%d(SB)", a->sym->name, a->offset); break; case D_STATIC: - snprint(str, sizeof(str), "%s<>+%ld(SB)", a->sym->name, + sprint(str, "%s<>+%d(SB)", a->sym->name, a->offset); break; case D_AUTO: - snprint(str, sizeof(str), "%s+%ld(SP)", a->sym->name, a->offset); + sprint(str, "%s+%d(SP)", a->sym->name, a->offset); break; case D_PARAM: if(a->sym) - snprint(str, sizeof(str), "%s+%ld(FP)", a->sym->name, a->offset); + sprint(str, "%s+%d(FP)", a->sym->name, a->offset); else - snprint(str, sizeof(str), "%ld(FP)", a->offset); + sprint(str, "%d(FP)", a->offset); break; case D_CONST: - snprint(str, sizeof(str), "$%ld", a->offset); + sprint(str, "$%d", a->offset); + break; + + case D_CONST2: + sprint(str, "$%d-%d", a->offset, a->offset2); break; case D_FCONST: - snprint(str, sizeof(str), "$(%.17e)", a->dval); + sprint(str, "$(%.17e)", a->dval); break; case D_SCONST: - snprint(str, sizeof(str), "$\"%S\"", a->sval); + sprint(str, "$\"%S\"", a->sval); break; case D_ADDR: a->type = a->index; a->index = D_NONE; - snprint(str, sizeof(str), "$%D", a); + sprint(str, "$%D", a); a->index = a->type; a->type = D_ADDR; goto conv; } brk: if(a->index != D_NONE) { - fmtstrcpy(fp, str); - snprint(s, sizeof(s), "(%R*%d)", (int)a->index, (int)a->scale); - return fmtstrcpy(fp, s); + sprint(s, "(%R*%d)", (int)a->index, (int)a->scale); + strcat(str, s); } conv: return fmtstrcpy(fp, str); @@ -152,7 +197,7 @@ char* regstr[] = { - "AL", /*[D_AL]*/ + "AL", /*[D_AL]*/ "CL", "DL", "BL", @@ -225,14 +270,14 @@ int Rconv(Fmt *fp) { - char str[20]; + char str[STRINGSZ]; int r; r = va_arg(fp->args, int); if(r >= D_AL && r <= D_NONE) - snprint(str, sizeof(str), "%s", regstr[r-D_AL]); + sprint(str, "%s", regstr[r-D_AL]); else - snprint(str, sizeof(str), "gok(%d)", r); + sprint(str, "gok(%d)", r); return fmtstrcpy(fp, str); } @@ -241,7 +286,7 @@ Sconv(Fmt *fp) { int i, c; - char str[30], *p, *a; + char str[STRINGSZ], *p, *a; a = va_arg(fp->args, char*); p = str; diff -r d8d00747375b sys/src/cmd/8c/machcap.c --- a/sys/src/cmd/8c/machcap.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/8c/machcap.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,9 +1,38 @@ +// Inferno utils/8c/machcap.c +// http://code.google.com/p/inferno-os/source/browse/utils/8c/machcap.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 "gc.h" int machcap(Node *n) { -// return 0; if(n == Z) return 1; /* test */ @@ -16,8 +45,6 @@ if(typechl[n->type->etype]) return 1; if(typev[n->type->etype]) { -// if(typev[n->type->etype] && n->right->op == OCONST) { -// if(hi64v(n->right) == 0) return 1; } break; @@ -83,7 +110,6 @@ case OHS: case OLO: case OLS: -//print("%O\n", n->op); return 1; } return 0; diff -r d8d00747375b sys/src/cmd/8c/mkenam --- a/sys/src/cmd/8c/mkenam Thu Sep 29 03:00:00 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -ed - ../8c/8.out.h <<'!' -v/^ A/d -,s/^ A/ "/ -g/ .*$/s/// -,s/,*$/",/ -1i -char* anames[] = -{ -. -$a -}; -. -w enam.c -Q -! diff -r d8d00747375b sys/src/cmd/8c/mkfile --- a/sys/src/cmd/8c/mkfile Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/8c/mkfile Mon Nov 14 17:35:25 2011 +0100 @@ -2,7 +2,6 @@ TARG=8c OFILES=\ - bound.$O\ cgen.$O\ cgen64.$O\ div.$O\ @@ -20,7 +19,7 @@ HFILES=\ gc.h\ - 8.out.h\ + ../8l/8.out.h\ ../cc/cc.h\ LIB=../cc/cc.a$O @@ -38,4 +37,7 @@ %.$O: ../cc/%.c $CC $CFLAGS ../cc/$stem.c +enam.c: ../8l/8.out.h + ape/psh ../8l/mkenam +CLEANFILES=enam.c diff -r d8d00747375b sys/src/cmd/8c/mul.c --- a/sys/src/cmd/8c/mul.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/8c/mul.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,3 +1,33 @@ +// Inferno utils/8c/mul.c +// http://code.google.com/p/inferno-os/source/browse/utils/8c/mul.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 "gc.h" typedef struct Malg Malg; @@ -10,7 +40,7 @@ struct Mparam { - ulong value; + uint32 value; char alg; char neg; char shift; @@ -34,10 +64,10 @@ * return position of lowest 1 */ int -lowbit(ulong v) +lowbit(uint32 v) { int s, i; - ulong m; + uint32 m; s = 0; m = 0xFFFFFFFFUL; @@ -67,13 +97,13 @@ } void -mulparam(ulong m, Mparam *mp) +mulparam(uint32 m, Mparam *mp) { int c, i, j, n, o, q, s; int bc, bi, bn, bo, bq, bs, bt; char *p; - long u; - ulong t; + int32 u; + uint32 t; bc = bq = 10; bi = bn = bo = bs = bt = 0; @@ -92,7 +122,7 @@ u = -u; } n = lowbit(u); - t = (ulong)u >> n; + t = (uint32)u >> n; switch(i) { case 0: if(t == 1) { @@ -291,9 +321,9 @@ void shiftit(Type *t, Node *s, Node *d) { - long c; + int32 c; - c = (long)s->vconst & 31; + c = (int32)s->vconst & 31; switch(c) { case 0: break; @@ -306,7 +336,7 @@ } static int -mulgen1(ulong v, Node *n) +mulgen1(uint32 v, Node *n) { int i, o; Mparam *p; @@ -325,7 +355,7 @@ mulparam(v, p); found: -// print("v=%.lx a=%d n=%d s=%d g=%d o=%d \n", p->value, p->alg, p->neg, p->shift, p->arg, p->off); +// print("v=%.x a=%d n=%d s=%d g=%d o=%d \n", p->value, p->alg, p->neg, p->shift, p->arg, p->off); if(p->alg < 0) return 0; diff -r d8d00747375b sys/src/cmd/8c/peep.c --- a/sys/src/cmd/8c/peep.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/8c/peep.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,3 +1,33 @@ +// Inferno utils/8c/peep.c +// http://code.google.com/p/inferno-os/source/browse/utils/8c/peep.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 "gc.h" static int @@ -67,8 +97,6 @@ pc = 0; /* speculating it won't kill */ loop1: - if(debug['b']) - comtarg(); t = 0; for(r=firstr; r!=R; r=r->link) { @@ -277,6 +305,9 @@ case ACWD: case ACDQ: + case ASTOSB: + case ASTOSL: + case AMOVSB: case AMOVSL: case AFSTSW: return 0; @@ -641,10 +672,21 @@ return 2; goto caseread; - case AMOVSL: case AREP: case AREPN: - if(v->type == D_CX || v->type == D_DI || v->type == D_SI) + if(v->type == D_CX) + return 2; + goto caseread; + + case AMOVSB: + case AMOVSL: + if(v->type == D_DI || v->type == D_SI) + return 2; + goto caseread; + + case ASTOSB: + case ASTOSL: + if(v->type == D_AX || v->type == D_DI) return 2; goto caseread; @@ -671,7 +713,7 @@ return 3; case ACALL: /* funny */ - if(REGARG>=0 && v->type == REGARG) + if(REGARG >= 0 && v->type == (uchar)REGARG) return 2; if(s != A) { diff -r d8d00747375b sys/src/cmd/8c/reg.c --- a/sys/src/cmd/8c/reg.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/8c/reg.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,3 +1,33 @@ +// Inferno utils/8c/reg.c +// http://code.google.com/p/inferno-os/source/browse/utils/8c/reg.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 "gc.h" Reg* @@ -36,13 +66,13 @@ Reg *r, *r1, *r2; Prog *p1; int i, z; - long initpc, val, npc; - ulong vreg; + int32 initpc, val, npc; + uint32 vreg; Bits bit; struct { - long m; - long c; + int32 m; + int32 c; Reg* p; } log5[6], *lp; @@ -224,7 +254,9 @@ */ case AFMOVDP: case AFMOVFP: + case AFMOVLP: case AFMOVVP: + case AFMOVWP: case ACALL: for(z=0; zlink) { - print("%ld:%P", r->loop, r->prog); + print("%d:%P", r->loop, r->prog); for(z=0; zuse1.b[z] | r->use2.b[z] | @@ -617,10 +649,10 @@ print("%P\t.a%P\n", p, p1); } -ulong +uint32 doregbits(int r) { - ulong b; + uint32 b; b = 0; if(r >= D_INDIR) @@ -641,7 +673,7 @@ { Var *v; int i, t, n, et, z; - long o; + int32 o; Bits bit; Sym *s; @@ -787,8 +819,8 @@ * such a node is a loop head. * recursively, all preds with a greater rpo number are in the loop */ -long -postorder(Reg *r, Reg **rpo2r, long n) +int32 +postorder(Reg *r, Reg **rpo2r, int32 n) { Reg *r1; @@ -804,10 +836,10 @@ return n; } -long -rpolca(long *idom, long rpo1, long rpo2) +int32 +rpolca(int32 *idom, int32 rpo1, int32 rpo2) { - long t; + int32 t; if(rpo1 == -1) return rpo2; @@ -828,7 +860,7 @@ } int -doms(long *idom, long r, long s) +doms(int32 *idom, int32 r, int32 s) { while(s > r) s = idom[s]; @@ -836,9 +868,9 @@ } int -loophead(long *idom, Reg *r) +loophead(int32 *idom, Reg *r) { - long src; + int32 src; src = r->rpo; if(r->p1 != R && doms(idom, src, r->p1->rpo)) @@ -850,7 +882,7 @@ } void -loopmark(Reg **rpo2r, long head, Reg *r) +loopmark(Reg **rpo2r, int32 head, Reg *r) { if(r->rpo < head || r->active == head) return; @@ -863,14 +895,14 @@ } void -loopit(Reg *r, long nr) +loopit(Reg *r, int32 nr) { Reg *r1; - long i, d, me; + int32 i, d, me; if(nr > maxnr) { rpo2r = alloc(nr * sizeof(Reg*)); - idom = alloc(nr * sizeof(long)); + idom = alloc(nr * sizeof(int32)); maxnr = nr; } @@ -933,8 +965,8 @@ } } -ulong -allreg(ulong b, Rgn *r) +uint32 +allreg(uint32 b, Rgn *r) { Var *v; int i; @@ -977,7 +1009,7 @@ Reg *r1; Prog *p; int z; - ulong bb; + uint32 bb; z = bn/32; bb = 1L<<(bn%32); @@ -999,7 +1031,7 @@ if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) { change -= CLOAD * r->loop; if(debug['R'] && debug['v']) - print("%ld%P\tld %B $%d\n", r->loop, + print("%d%P\td %B $%d\n", r->loop, r->prog, blsh(bn), change); } for(;;) { @@ -1012,7 +1044,7 @@ if(BtoR(bb) != D_F0) change = -CINF; if(debug['R'] && debug['v']) - print("%ld%P\tu1 %B $%d\n", r->loop, + print("%d%P\tu1 %B $%d\n", r->loop, p, blsh(bn), change); } @@ -1022,7 +1054,7 @@ if(BtoR(bb) != D_F0) change = -CINF; if(debug['R'] && debug['v']) - print("%ld%P\tu2 %B $%d\n", r->loop, + print("%d%P\tu2 %B $%d\n", r->loop, p, blsh(bn), change); } @@ -1032,7 +1064,7 @@ if(BtoR(bb) != D_F0) change = -CINF; if(debug['R'] && debug['v']) - print("%ld%P\tst %B $%d\n", r->loop, + print("%d%P\tst %B $%d\n", r->loop, p, blsh(bn), change); } @@ -1057,10 +1089,10 @@ } } -ulong -regset(Reg *r, ulong bb) +uint32 +regset(Reg *r, uint32 bb) { - ulong b, set; + uint32 b, set; Adr v; int c; @@ -1076,10 +1108,10 @@ return set; } -ulong -reguse(Reg *r, ulong bb) +uint32 +reguse(Reg *r, uint32 bb) { - ulong b, set; + uint32 b, set; Adr v; int c; @@ -1095,12 +1127,12 @@ return set; } -ulong +uint32 paint2(Reg *r, int bn) { Reg *r1; int z; - ulong bb, vreg, x; + uint32 bb, vreg, x; z = bn/32; bb = 1L << (bn%32); @@ -1156,12 +1188,12 @@ } void -paint3(Reg *r, int bn, long rb, int rn) +paint3(Reg *r, int bn, int32 rb, int rn) { Reg *r1; Prog *p; int z; - ulong bb; + uint32 bb; z = bn/32; bb = 1L << (bn%32); @@ -1235,7 +1267,7 @@ a->type = rn; } -long +int32 RtoB(int r) { @@ -1245,7 +1277,7 @@ } int -BtoR(long b) +BtoR(int32 b) { b &= 0xffL; diff -r d8d00747375b sys/src/cmd/8c/sgen.c --- a/sys/src/cmd/8c/sgen.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/8c/sgen.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,5 +1,52 @@ +// Inferno utils/8c/sgen.c +// http://code.google.com/p/inferno-os/source/browse/utils/8c/sgen.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 "gc.h" +Prog* +gtext(Sym *s, int32 stkoff) +{ + int32 a; + + a = 0; + if(!(textflag & NOSPLIT)) + a = argsize(); + else if(stkoff >= 128) + yyerror("stack frame too large for NOSPLIT function"); + + gpseudo(ATEXT, s, nodconst(stkoff)); + p->to.type = D_CONST2; + p->to.offset2 = a; + return p; +} + void noretval(int n) { @@ -12,9 +59,6 @@ gins(ANOP, Z, Z); p->to.type = FREGRET; } - if((n&3) == 3) - if(thisfn && thisfn->link && typefd[thisfn->link->etype]) - gins(AFLDZ, Z, Z); } /* welcome to commute */ @@ -62,6 +106,7 @@ * (20) * (X) ==> 7 multiplier in indexing * (X,7) + (13,1) ==> 8 adder in indexing (addresses) * (8) ==> &9(OINDEX) index, almost addressable + * 100 extern register * * calculate complexity (number of registers) */ @@ -88,6 +133,10 @@ n->addable = 11; break; + case OEXREG: + n->addable = 0; + break; + case OREGISTER: n->addable = 12; break; diff -r d8d00747375b sys/src/cmd/8c/swt.c --- a/sys/src/cmd/8c/swt.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/8c/swt.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,7 +1,37 @@ +// Inferno utils/8c/swt.c +// http://code.google.com/p/inferno-os/source/browse/utils/8c/swt.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 "gc.h" void -swit1(C1 *q, int nc, long def, Node *n) +swit1(C1 *q, int nc, int32 def, Node *n) { C1 *r; int i; @@ -10,7 +40,7 @@ if(nc < 5) { for(i=0; ival); + print("case = %.8ux\n", q->val); gopcode(OEQ, n->type, n, nodconst(q->val)); patch(p, q->label); q++; @@ -22,7 +52,7 @@ i = nc / 2; r = q+i; if(debug['W']) - print("case > %.8lux\n", r->val); + print("case > %.8ux\n", r->val); gopcode(OGT, n->type, n, nodconst(r->val)); sp = p; gbranch(OGOTO); @@ -31,7 +61,7 @@ swit1(q, i, def, n); if(debug['W']) - print("case < %.8lux\n", r->val); + print("case < %.8ux\n", r->val); patch(sp, pc); swit1(r+1, nc-i-1, def, n); } @@ -40,7 +70,7 @@ bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn) { int sh; - long v; + int32 v; Node *l; /* @@ -78,7 +108,7 @@ void bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn) { - long v; + int32 v; Node nod; int sh; @@ -102,10 +132,10 @@ regfree(n3); } -long -outstring(char *s, long n) +int32 +outstring(char *s, int32 n) { - long r; + int32 r; if(suppress) return nstring; @@ -128,9 +158,9 @@ } void -sextern(Sym *s, Node *a, long o, long w) +sextern(Sym *s, Node *a, int32 o, int32 w) { - long e, lw; + int32 e, lw; for(e=0; eop == OCONST && typev[a->type->etype]) { gpseudo(ADATA, s, lo64(a)); @@ -199,7 +229,24 @@ return; } Binit(&b, f, OWRITE); - Bseek(&b, 0L, 2); + + Bprint(&b, "go object %s %s %s\n", getgoos(), thestring, getgoversion()); + if(ndynimp > 0 || ndynexp > 0) { + int i; + + Bprint(&b, "\n"); + Bprint(&b, "$$ // exports\n\n"); + Bprint(&b, "$$ // local types\n\n"); + Bprint(&b, "$$ // dynimport\n"); + for(i=0; ilink) { p = h->name; op = 0; - /* on windows skip drive specifier in pathname */ if(systemtype(Windows) && p && p[1] == ':'){ - p += 2; - c = *p; - } - if(p && p[0] != c && h->offset == 0 && pathname){ - /* on windows skip drive specifier in pathname */ + c = p[2]; + } else if(p && p[0] != c && h->offset == 0 && pathname){ if(systemtype(Windows) && pathname[1] == ':') { op = p; - p = pathname+2; - c = *p; + p = pathname; + c = p[2]; } else if(pathname[0] == c){ op = p; p = pathname; @@ -348,7 +391,7 @@ zname(Biobuf *b, Sym *s, int t) { char *n; - ulong sig; + uint32 sig; if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){ sig = sign(s); @@ -377,7 +420,7 @@ void zaddr(Biobuf *b, Adr *a, int s) { - long l; + int32 l; int i, t; char *n; Ieee e; @@ -401,6 +444,9 @@ case D_SCONST: t |= T_SCONST; break; + case D_CONST2: + t |= T_OFFSET|T_OFFSET2; + break; } Bputc(b, t); @@ -415,6 +461,13 @@ Bputc(b, l>>16); Bputc(b, l>>24); } + if(t & T_OFFSET2) { /* implies offset2 */ + l = a->offset2; + Bputc(b, l); + Bputc(b, l>>8); + Bputc(b, l>>16); + Bputc(b, l>>24); + } if(t & T_SYM) /* implies sym */ Bputc(b, s); if(t & T_FCONST) { @@ -443,10 +496,10 @@ Bputc(b, a->type); } -long -align(long i, Type *t, int op) +int32 +align(int32 i, Type *t, int op, int32 *maxalign) { - long o; + int32 o; Type *v; int w; @@ -458,18 +511,26 @@ break; case Asu2: /* padding at end of a struct */ - w = SZ_LONG; + w = *maxalign; + if(w < 1) + w = 1; if(packflg) w = packflg; break; - case Ael1: /* initial allign of struct element */ + case Ael1: /* initial align of struct element */ for(v=t; v->etype==TARRAY; v=v->link) ; - w = ewidth[v->etype]; - if(w <= 0 || w >= SZ_LONG) - w = SZ_LONG; - if(packflg) + if(v->etype == TSTRUCT || v->etype == TUNION) + w = v->align; + else { + w = ewidth[v->etype]; + if(w == 8) + w = 4; + } + if(w < 1 || w > SZ_LONG) + fatal(Z, "align"); + if(packflg) w = packflg; break; @@ -479,12 +540,12 @@ case Aarg0: /* initial passbyptr argument in arg list */ if(typesuv[t->etype]) { - o = align(o, types[TIND], Aarg1); - o = align(o, types[TIND], Aarg2); + o = align(o, types[TIND], Aarg1, nil); + o = align(o, types[TIND], Aarg2, nil); } break; - case Aarg1: /* initial allign of parameter */ + case Aarg1: /* initial align of parameter */ w = ewidth[t->etype]; if(w <= 0 || w >= SZ_LONG) { w = SZ_LONG; @@ -495,25 +556,29 @@ case Aarg2: /* width of a parameter */ o += t->width; - w = SZ_LONG; + w = t->width; + if(w > SZ_LONG) + w = SZ_LONG; break; - case Aaut3: /* total allign of automatic */ - o = align(o, t, Ael1); - o = align(o, t, Ael2); + case Aaut3: /* total align of automatic */ + o = align(o, t, Ael1, nil); + o = align(o, t, Ael2, nil); break; } - o = round(o, w); + o = xround(o, w); + if(maxalign && *maxalign < w) + *maxalign = w; if(debug['A']) - print("align %s %ld %T = %ld\n", bnames[op], i, t, o); + print("align %s %d %T = %d\n", bnames[op], i, t, o); return o; } -long -maxround(long max, long v) +int32 +maxround(int32 max, int32 v) { v += SZ_LONG-1; if(v > max) - max = round(v, SZ_LONG); + max = xround(v, SZ_LONG); return max; } diff -r d8d00747375b sys/src/cmd/8c/txt.c --- a/sys/src/cmd/8c/txt.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/8c/txt.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,3 +1,33 @@ +// Inferno utils/8c/txt.c +// http://code.google.com/p/inferno-os/source/browse/utils/8c/txt.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 "gc.h" void @@ -143,7 +173,7 @@ void gargs(Node *n, Node *tn1, Node *tn2) { - long regs; + int32 regs; Node fnxargs[20], *fnxp; regs = cursafe; @@ -203,7 +233,7 @@ sugen(n, tn2, n->type->width); return; } - if(REGARG>=0 && curarg == 0 && typeilp[n->type->etype]) { + if(REGARG >= 0 && curarg == 0 && typeilp[n->type->etype]) { regaalloc1(tn1, n); if(n->complex >= FNX) { cgen(*fnxp, tn1); @@ -229,7 +259,7 @@ } Node* -nodconst(long v) +nodconst(int32 v) { constnode.vconst = v; return &constnode; @@ -321,7 +351,6 @@ if(i) reg[i]++; nodreg(n, tn, i); -//print("+ %R %d\n", i, reg[i]); } void @@ -348,7 +377,6 @@ if(reg[i] <= 0) goto err; reg[i]--; -//print("- %R %d\n", i, reg[i]); return; err: diag(n, "error in regfree: %R", i); @@ -357,7 +385,7 @@ void regsalloc(Node *n, Node *nn) { - cursafe = align(cursafe, nn->type, Aaut3); + cursafe = align(cursafe, nn->type, Aaut3, nil); maxargsafe = maxround(maxargsafe, cursafe+curarg); *n = *nodsafe; n->xoffset = -(stkoff + cursafe); @@ -369,32 +397,28 @@ void regaalloc1(Node *n, Node *nn) { - USED(nn); - if(REGARG < 0) { - diag(n, "regaalloc1"); + fatal(n, "regaalloc1 and REGARG<0"); return; } -/* not reached nodreg(n, nn, REGARG); reg[REGARG]++; - curarg = align(curarg, nn->type, Aarg1); - curarg = align(curarg, nn->type, Aarg2); + curarg = align(curarg, nn->type, Aarg1, nil); + curarg = align(curarg, nn->type, Aarg2, nil); maxargsafe = maxround(maxargsafe, cursafe+curarg); -*/ } void regaalloc(Node *n, Node *nn) { - curarg = align(curarg, nn->type, Aarg1); + curarg = align(curarg, nn->type, Aarg1, nil); *n = *nn; n->op = OINDREG; n->reg = REGSP; n->xoffset = curarg; n->complex = 0; n->addable = 20; - curarg = align(curarg, nn->type, Aarg2); + curarg = align(curarg, nn->type, Aarg2, nil); maxargsafe = maxround(maxargsafe, cursafe+curarg); } @@ -413,7 +437,7 @@ void naddr(Node *n, Adr *a) { - long v; + int32 v; a->type = D_NONE; if(n == Z) @@ -422,7 +446,6 @@ default: bad: diag(n, "bad in naddr: %O %D", n->op, a); -//prtree(n, "naddr"); break; case OREGISTER: @@ -430,6 +453,10 @@ a->sym = S; break; + case OEXREG: + a->type = D_INDIR + D_GS; + a->offset = n->reg - 1; + break; case OIND: naddr(n->left, a); @@ -798,7 +825,9 @@ case CASE( TFLOAT, TSHORT): case CASE( TFLOAT, TUSHORT): case CASE( TFLOAT, TINT): + case CASE( TFLOAT, TUINT): case CASE( TFLOAT, TLONG): + case CASE( TFLOAT, TULONG): case CASE( TFLOAT, TIND): case CASE( TDOUBLE,TCHAR): @@ -806,8 +835,20 @@ case CASE( TDOUBLE,TSHORT): case CASE( TDOUBLE,TUSHORT): case CASE( TDOUBLE,TINT): + case CASE( TDOUBLE,TUINT): case CASE( TDOUBLE,TLONG): + case CASE( TDOUBLE,TULONG): case CASE( TDOUBLE,TIND): + + case CASE( TVLONG, TCHAR): + case CASE( TVLONG, TUCHAR): + case CASE( TVLONG, TSHORT): + case CASE( TVLONG, TUSHORT): + case CASE( TVLONG, TINT): + case CASE( TVLONG, TUINT): + case CASE( TVLONG, TLONG): + case CASE( TVLONG, TULONG): + case CASE( TVLONG, TIND): if(fproundflg) { regsalloc(&nod, ®node); gins(AFMOVLP, f, &nod); @@ -827,26 +868,13 @@ return; /* - * float to ulong - */ - case CASE( TDOUBLE, TULONG): - case CASE( TFLOAT, TULONG): - case CASE( TDOUBLE, TUINT): - case CASE( TFLOAT, TUINT): - regsalloc(&nod, ®node); - gmove(f, &fregnode0); - gins(AFADDD, nodfconst(-2147483648.), &fregnode0); - gins(AFMOVLP, f, &nod); - gins(ASUBL, nodconst(-2147483648), &nod); - gmove(&nod, t); - return; - -/* * ulong to float */ case CASE( TULONG, TDOUBLE): + case CASE( TULONG, TVLONG): case CASE( TULONG, TFLOAT): case CASE( TUINT, TDOUBLE): + case CASE( TUINT, TVLONG): case CASE( TUINT, TFLOAT): regalloc(&nod, f, f); gmove(f, &nod); @@ -879,6 +907,14 @@ case CASE( TINT, TDOUBLE): case CASE( TLONG, TDOUBLE): case CASE( TIND, TDOUBLE): + + case CASE( TCHAR, TVLONG): + case CASE( TUCHAR, TVLONG): + case CASE( TSHORT, TVLONG): + case CASE( TUSHORT,TVLONG): + case CASE( TINT, TVLONG): + case CASE( TLONG, TVLONG): + case CASE( TIND, TVLONG): regsalloc(&nod, ®node); gmove(f, &nod); gins(AFMOVL, &nod, &fregnode0); @@ -889,9 +925,15 @@ */ case CASE( TFLOAT, TFLOAT): case CASE( TDOUBLE,TFLOAT): + case CASE( TVLONG, TFLOAT): case CASE( TFLOAT, TDOUBLE): case CASE( TDOUBLE,TDOUBLE): + case CASE( TVLONG, TDOUBLE): + + case CASE( TFLOAT, TVLONG): + case CASE( TDOUBLE,TVLONG): + case CASE( TVLONG, TVLONG): a = AFMOVD; break; } if(a == AMOVL || a == AFMOVD) @@ -904,7 +946,7 @@ doindex(Node *n) { Node nod, nod1; - long v; + int32 v; if(debug['Y']) prtree(n, "index"); @@ -919,7 +961,6 @@ if(n->left->op == OCONST) idx.ptr = D_CONST; else if(n->left->op == OREGISTER) -// else if(n->left->op == OREGISTER && typeil[n->left->type->etype]) idx.ptr = n->left->reg; else if(n->left->op != OADDR) { reg[D_BP]++; // cant be used as a base @@ -1315,7 +1356,7 @@ } void -patch(Prog *op, long pc) +patch(Prog *op, int32 pc) { op->to.offset = pc; @@ -1330,7 +1371,9 @@ p->as = a; p->from.type = D_EXTERN; p->from.sym = s; - p->from.scale = (profileflg ? 0 : NOPROF); + p->from.scale = textflag; + textflag = 0; + if(s->class == CSTATIC) p->from.type = D_STATIC; naddr(n, &p->to); @@ -1341,7 +1384,7 @@ int sconst(Node *n) { - long v; + int32 v; if(n->op == OCONST && !typefd[n->type->etype]) { v = n->vconst; @@ -1351,18 +1394,26 @@ return 0; } -long +int32 exreg(Type *t) { + int32 o; - USED(t); + if(typechlp[t->etype]){ + if(exregoffset >= 32) + return 0; + o = exregoffset; + exregoffset += 4; + return o+1; // +1 to avoid 0 == failure; naddr case OEXREG will -1. + } + return 0; } schar ewidth[NTYPE] = { - -1, /*[TXXX]*/ - SZ_CHAR, /*[TCHAR]*/ + -1, /*[TXXX]*/ + SZ_CHAR, /*[TCHAR]*/ SZ_CHAR, /*[TUCHAR]*/ SZ_SHORT, /*[TSHORT]*/ SZ_SHORT, /*[TUSHORT]*/ @@ -1382,14 +1433,14 @@ -1, /*[TUNION]*/ SZ_INT, /*[TENUM]*/ }; -long ncast[NTYPE] = +int32 ncast[NTYPE] = { 0, /*[TXXX]*/ BCHAR|BUCHAR, /*[TCHAR]*/ - BCHAR|BUCHAR, /*[TUCHAR]*/ + BCHAR|BUCHAR, /*[TUCHAR]*/ BSHORT|BUSHORT, /*[TSHORT]*/ BSHORT|BUSHORT, /*[TUSHORT]*/ - BINT|BUINT|BLONG|BULONG|BIND, /*[TINT]*/ + BINT|BUINT|BLONG|BULONG|BIND, /*[TINT]*/ BINT|BUINT|BLONG|BULONG|BIND, /*[TUINT]*/ BINT|BUINT|BLONG|BULONG|BIND, /*[TLONG]*/ BINT|BUINT|BLONG|BULONG|BIND, /*[TULONG]*/ diff -r d8d00747375b sys/src/cmd/8l/8.out.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/src/cmd/8l/8.out.h Mon Nov 14 17:35:25 2011 +0100 @@ -0,0 +1,544 @@ +// Inferno utils/8c/8.out.h +// http://code.google.com/p/inferno-os/source/browse/utils/8c/8.out.h +// +// 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. + +#define NSYM 50 +#define NSNAME 8 +#define NOPROF (1<<0) +#define DUPOK (1<<1) +#define NOSPLIT (1<<2) +#define RODATA (1<<3) + +enum as +{ + AXXX, + AAAA, + AAAD, + AAAM, + AAAS, + AADCB, + AADCL, + AADCW, + AADDB, + AADDL, + AADDW, + AADJSP, + AANDB, + AANDL, + AANDW, + AARPL, + ABOUNDL, + ABOUNDW, + ABSFL, + ABSFW, + ABSRL, + ABSRW, + ABTL, + ABTW, + ABTCL, + ABTCW, + ABTRL, + ABTRW, + ABTSL, + ABTSW, + ABYTE, + ACALL, + ACLC, + ACLD, + ACLI, + ACLTS, + ACMC, + ACMPB, + ACMPL, + ACMPW, + ACMPSB, + ACMPSL, + ACMPSW, + ADAA, + ADAS, + ADATA, + ADECB, + ADECL, + ADECW, + ADIVB, + ADIVL, + ADIVW, + AENTER, + AGLOBL, + AGOK, + AHISTORY, + AHLT, + AIDIVB, + AIDIVL, + AIDIVW, + AIMULB, + AIMULL, + AIMULW, + AINB, + AINL, + AINW, + AINCB, + AINCL, + AINCW, + AINSB, + AINSL, + AINSW, + AINT, + AINTO, + AIRETL, + AIRETW, + AJCC, + AJCS, + AJCXZL, + AJCXZW, + AJEQ, + AJGE, + AJGT, + AJHI, + AJLE, + AJLS, + AJLT, + AJMI, + AJMP, + AJNE, + AJOC, + AJOS, + AJPC, + AJPL, + AJPS, + ALAHF, + ALARL, + ALARW, + ALEAL, + ALEAW, + ALEAVEL, + ALEAVEW, + ALOCK, + ALODSB, + ALODSL, + ALODSW, + ALONG, + ALOOP, + ALOOPEQ, + ALOOPNE, + ALSLL, + ALSLW, + AMOVB, + AMOVL, + AMOVW, + AMOVBLSX, + AMOVBLZX, + AMOVBWSX, + AMOVBWZX, + AMOVWLSX, + AMOVWLZX, + AMOVSB, + AMOVSL, + AMOVSW, + AMULB, + AMULL, + AMULW, + ANAME, + ANEGB, + ANEGL, + ANEGW, + ANOP, + ANOTB, + ANOTL, + ANOTW, + AORB, + AORL, + AORW, + AOUTB, + AOUTL, + AOUTW, + AOUTSB, + AOUTSL, + AOUTSW, + APAUSE, + APOPAL, + APOPAW, + APOPFL, + APOPFW, + APOPL, + APOPW, + APUSHAL, + APUSHAW, + APUSHFL, + APUSHFW, + APUSHL, + APUSHW, + ARCLB, + ARCLL, + ARCLW, + ARCRB, + ARCRL, + ARCRW, + AREP, + AREPN, + ARET, + AROLB, + AROLL, + AROLW, + ARORB, + ARORL, + ARORW, + ASAHF, + ASALB, + ASALL, + ASALW, + ASARB, + ASARL, + ASARW, + ASBBB, + ASBBL, + ASBBW, + ASCASB, + ASCASL, + ASCASW, + ASETCC, + ASETCS, + ASETEQ, + ASETGE, + ASETGT, + ASETHI, + ASETLE, + ASETLS, + ASETLT, + ASETMI, + ASETNE, + ASETOC, + ASETOS, + ASETPC, + ASETPL, + ASETPS, + ACDQ, + ACWD, + ASHLB, + ASHLL, + ASHLW, + ASHRB, + ASHRL, + ASHRW, + ASTC, + ASTD, + ASTI, + ASTOSB, + ASTOSL, + ASTOSW, + ASUBB, + ASUBL, + ASUBW, + ASYSCALL, + ATESTB, + ATESTL, + ATESTW, + ATEXT, + AVERR, + AVERW, + AWAIT, + AWORD, + AXCHGB, + AXCHGL, + AXCHGW, + AXLAT, + AXORB, + AXORL, + AXORW, + + AFMOVB, + AFMOVBP, + AFMOVD, + AFMOVDP, + AFMOVF, + AFMOVFP, + AFMOVL, + AFMOVLP, + AFMOVV, + AFMOVVP, + AFMOVW, + AFMOVWP, + AFMOVX, + AFMOVXP, + + AFCOMB, + AFCOMBP, + AFCOMD, + AFCOMDP, + AFCOMDPP, + AFCOMF, + AFCOMFP, + AFCOMI, + AFCOMIP, + AFCOML, + AFCOMLP, + AFCOMW, + AFCOMWP, + AFUCOM, + AFUCOMI, + AFUCOMIP, + AFUCOMP, + AFUCOMPP, + + AFADDDP, + AFADDW, + AFADDL, + AFADDF, + AFADDD, + + AFMULDP, + AFMULW, + AFMULL, + AFMULF, + AFMULD, + + AFSUBDP, + AFSUBW, + AFSUBL, + AFSUBF, + AFSUBD, + + AFSUBRDP, + AFSUBRW, + AFSUBRL, + AFSUBRF, + AFSUBRD, + + AFDIVDP, + AFDIVW, + AFDIVL, + AFDIVF, + AFDIVD, + + AFDIVRDP, + AFDIVRW, + AFDIVRL, + AFDIVRF, + AFDIVRD, + + AFXCHD, + AFFREE, + + AFLDCW, + AFLDENV, + AFRSTOR, + AFSAVE, + AFSTCW, + AFSTENV, + AFSTSW, + + AF2XM1, + AFABS, + AFCHS, + AFCLEX, + AFCOS, + AFDECSTP, + AFINCSTP, + AFINIT, + AFLD1, + AFLDL2E, + AFLDL2T, + AFLDLG2, + AFLDLN2, + AFLDPI, + AFLDZ, + AFNOP, + AFPATAN, + AFPREM, + AFPREM1, + AFPTAN, + AFRNDINT, + AFSCALE, + AFSIN, + AFSINCOS, + AFSQRT, + AFTST, + AFXAM, + AFXTRACT, + AFYL2X, + AFYL2XP1, + + AEND, + + ADYNT_, + AINIT_, + + ASIGNAME, + + ACMPXCHGB, + ACMPXCHGL, + ACMPXCHGW, + ACMPXCHG8B, + + AXADDB, + AXADDL, + AXADDW, + + /* conditional move */ + ACMOVLCC, + ACMOVLCS, + ACMOVLEQ, + ACMOVLGE, + ACMOVLGT, + ACMOVLHI, + ACMOVLLE, + ACMOVLLS, + ACMOVLLT, + ACMOVLMI, + ACMOVLNE, + ACMOVLOC, + ACMOVLOS, + ACMOVLPC, + ACMOVLPL, + ACMOVLPS, + ACMOVWCC, + ACMOVWCS, + ACMOVWEQ, + ACMOVWGE, + ACMOVWGT, + ACMOVWHI, + ACMOVWLE, + ACMOVWLS, + ACMOVWLT, + ACMOVWMI, + ACMOVWNE, + ACMOVWOC, + ACMOVWOS, + ACMOVWPC, + ACMOVWPL, + ACMOVWPS, + + AFCMOVCC, + AFCMOVCS, + AFCMOVEQ, + AFCMOVHI, + AFCMOVLS, + AFCMOVNE, + AFCMOVNU, + AFCMOVUN, + + ALAST +}; + +enum +{ + D_AL = 0, + D_CL, + D_DL, + D_BL, + + D_AH = 4, + D_CH, + D_DH, + D_BH, + + D_AX = 8, + D_CX, + D_DX, + D_BX, + D_SP, + D_BP, + D_SI, + D_DI, + + D_F0 = 16, + D_F7 = D_F0 + 7, + + D_CS = 24, + D_SS, + D_DS, + D_ES, + D_FS, + D_GS, + + D_GDTR, /* global descriptor table register */ + D_IDTR, /* interrupt descriptor table register */ + D_LDTR, /* local descriptor table register */ + D_MSW, /* machine status word */ + D_TASK, /* task register */ + + D_CR = 35, + D_DR = 43, + D_TR = 51, + + D_NONE = 59, + + D_BRANCH = 60, + D_EXTERN = 61, + D_STATIC = 62, + D_AUTO = 63, + D_PARAM = 64, + D_CONST = 65, + D_FCONST = 66, + D_SCONST = 67, + D_ADDR = 68, + + D_FILE, + D_FILE1, + + D_INDIR, /* additive */ + + D_CONST2 = D_INDIR+D_INDIR, + D_SIZE, /* 8l internal */ + D_PCREL, + D_GOTOFF, + D_GOTREL, + + T_TYPE = 1<<0, + T_INDEX = 1<<1, + T_OFFSET = 1<<2, + T_FCONST = 1<<3, + T_SYM = 1<<4, + T_SCONST = 1<<5, + T_OFFSET2 = 1<<6, + T_GOTYPE = 1<<7, + + REGARG = -1, + REGRET = D_AX, + FREGRET = D_F0, + REGSP = D_SP, + REGTMP = D_DI, +}; + +/* + * this is the ranlib header + */ +#define SYMDEF "__.SYMDEF" + +/* + * this is the simulated IEEE floating point + */ +typedef struct ieee Ieee; +struct ieee +{ + int32 l; /* contains ls-man 0xffffffff */ + int32 h; /* contains sign 0x80000000 + exp 0x7ff00000 + ms-man 0x000fffff */ +}; diff -r d8d00747375b sys/src/cmd/8l/asm.c --- a/sys/src/cmd/8l/asm.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/8l/asm.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,10 +1,49 @@ +// 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. + +// Writing object files. + #include "l.h" +#include "../ld/lib.h" +#include "../ld/elf.h" +#include "../ld/dwarf.h" +#include "../ld/macho.h" +#include "../ld/pe.h" #define Dbufslop 100 -#define PADDR(a) ((ulong)(a) & ~0xF0000000) +char linuxdynld[] = "/lib/ld-linux.so.2"; +char freebsddynld[] = "/usr/libexec/ld-elf.so.1"; +char openbsddynld[] = "/usr/libexec/ld.so"; -long +int32 entryvalue(void) { char *a; @@ -16,219 +55,771 @@ 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: + if(s->type != STEXT) diag("entry not text: %s", s->name); - } return s->value; } +vlong +datoff(vlong addr) +{ + if(addr >= segdata.vaddr) + return addr - segdata.vaddr + segdata.fileoff; + if(addr >= segtext.vaddr) + return addr - segtext.vaddr + segtext.fileoff; + diag("datoff %#llx", addr); + return 0; +} + +enum { + ElfStrEmpty, + ElfStrInterp, + ElfStrHash, + ElfStrGot, + ElfStrGotPlt, + ElfStrDynamic, + ElfStrDynsym, + ElfStrDynstr, + ElfStrRel, + ElfStrText, + ElfStrData, + ElfStrBss, + ElfStrShstrtab, + ElfStrSymtab, + ElfStrStrtab, + ElfStrRelPlt, + ElfStrPlt, + ElfStrGnuVersion, + ElfStrGnuVersionR, + NElfStr +}; + +vlong elfstr[NElfStr]; + +static int +needlib(char *name) +{ + char *p; + Sym *s; + + if(*name == '\0') + return 0; + + /* 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; +} + +int nelfsym = 1; + +static void addpltsym(Sym*); +static void addgotsym(Sym*); + void -wputl(ushort w) +adddynrel(Sym *s, Reloc *r) { - cput(w); - cput(w>>8); + Sym *targ, *rel, *got; + + targ = r->sym; + cursym = s; + + switch(r->type) { + default: + if(r->type >= 256) { + diag("unexpected relocation type %d", r->type); + return; + } + break; + + // Handle relocations found in ELF object files. + case 256 + R_386_PC32: + if(targ->dynimpname != nil && !targ->dynexport) + diag("unexpected R_386_PC32 relocation for dynamic symbol %s", targ->name); + if(targ->type == 0 || targ->type == SXREF) + diag("unknown symbol %s in pcrel", targ->name); + r->type = D_PCREL; + r->add += 4; + return; + + case 256 + R_386_PLT32: + r->type = D_PCREL; + r->add += 4; + if(targ->dynimpname != nil && !targ->dynexport) { + addpltsym(targ); + r->sym = lookup(".plt", 0); + r->add += targ->plt; + } + return; + + case 256 + R_386_GOT32: + if(targ->dynimpname == nil || targ->dynexport) { + // have symbol + // turn MOVL of GOT entry into LEAL of symbol itself + if(r->off < 2 || s->p[r->off-2] != 0x8b) { + diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name); + return; + } + s->p[r->off-2] = 0x8d; + r->type = D_GOTOFF; + return; + } + addgotsym(targ); + r->type = D_CONST; // write r->add during relocsym + r->sym = S; + r->add += targ->got; + return; + + case 256 + R_386_GOTOFF: + r->type = D_GOTOFF; + return; + + case 256 + R_386_GOTPC: + r->type = D_PCREL; + r->sym = lookup(".got", 0); + r->add += 4; + return; + + case 256 + R_386_32: + if(targ->dynimpname != nil && !targ->dynexport) + diag("unexpected R_386_32 relocation for dynamic symbol %s", targ->name); + r->type = D_ADDR; + return; + + case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 0: + r->type = D_ADDR; + if(targ->dynimpname != nil && !targ->dynexport) + diag("unexpected reloc for dynamic symbol %s", targ->name); + return; + + case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 1: + if(targ->dynimpname != nil && !targ->dynexport) { + addpltsym(targ); + r->sym = lookup(".plt", 0); + r->add = targ->plt; + r->type = D_PCREL; + return; + } + r->type = D_PCREL; + return; + + case 512 + MACHO_FAKE_GOTPCREL: + if(targ->dynimpname == nil || targ->dynexport) { + // have symbol + // turn MOVL of GOT entry into LEAL of symbol itself + if(r->off < 2 || s->p[r->off-2] != 0x8b) { + diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name); + return; + } + s->p[r->off-2] = 0x8d; + r->type = D_PCREL; + return; + } + addgotsym(targ); + r->sym = lookup(".got", 0); + r->add += targ->got; + r->type = D_PCREL; + return; + } + + // Handle references to ELF symbols from our own object files. + if(targ->dynimpname == nil || targ->dynexport) + return; + + switch(r->type) { + case D_PCREL: + addpltsym(targ); + r->sym = lookup(".plt", 0); + r->add = targ->plt; + return; + + case D_ADDR: + if(s->type != SDATA) + break; + if(iself) { + adddynsym(targ); + rel = lookup(".rel", 0); + addaddrplus(rel, s, r->off); + adduint32(rel, ELF32_R_INFO(targ->dynid, R_386_32)); + r->type = D_CONST; // write r->add during relocsym + r->sym = S; + return; + } + if(HEADTYPE == Hdarwin && s->size == PtrSize && r->off == 0) { + // Mach-O relocations are a royal pain to lay out. + // They use a compact stateful bytecode representation + // that is too much bother to deal with. + // Instead, interpret the C declaration + // void *_Cvar_stderr = &stderr; + // as making _Cvar_stderr the name of a GOT entry + // for stderr. This is separate from the usual GOT entry, + // just in case the C code assigns to the variable, + // and of course it only works for single pointers, + // but we only need to support cgo and that's all it needs. + adddynsym(targ); + got = lookup(".got", 0); + s->type = got->type | SSUB; + s->outer = got; + s->sub = got->sub; + got->sub = s; + s->value = got->size; + adduint32(got, 0); + adduint32(lookup(".linkedit.got", 0), targ->dynid); + r->type = 256; // ignore during relocsym + return; + } + break; + } + + cursym = s; + diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type); +} + +static void +elfsetupplt(void) +{ + Sym *plt, *got; + + plt = lookup(".plt", 0); + got = lookup(".got.plt", 0); + if(plt->size == 0) { + // pushl got+4 + adduint8(plt, 0xff); + adduint8(plt, 0x35); + addaddrplus(plt, got, 4); + + // jmp *got+8 + adduint8(plt, 0xff); + adduint8(plt, 0x25); + addaddrplus(plt, got, 8); + + // zero pad + adduint32(plt, 0); + + // assume got->size == 0 too + addaddrplus(got, lookup(".dynamic", 0), 0); + adduint32(got, 0); + adduint32(got, 0); + } +} + +int +archreloc(Reloc *r, Sym *s, vlong *val) +{ + USED(s); + switch(r->type) { + case D_CONST: + *val = r->add; + return 0; + case D_GOTOFF: + *val = symaddr(r->sym) + r->add - symaddr(lookup(".got", 0)); + return 0; + } + return -1; +} + +static void +addpltsym(Sym *s) +{ + Sym *plt, *got, *rel; + + if(s->plt >= 0) + return; + + adddynsym(s); + + if(iself) { + plt = lookup(".plt", 0); + got = lookup(".got.plt", 0); + rel = lookup(".rel.plt", 0); + if(plt->size == 0) + elfsetupplt(); + + // jmpq *got+size + adduint8(plt, 0xff); + adduint8(plt, 0x25); + addaddrplus(plt, got, got->size); + + // add to got: pointer to current pos in plt + addaddrplus(got, plt, plt->size); + + // pushl $x + adduint8(plt, 0x68); + adduint32(plt, rel->size); + + // jmp .plt + adduint8(plt, 0xe9); + adduint32(plt, -(plt->size+4)); + + // rel + addaddrplus(rel, got, got->size-4); + adduint32(rel, ELF32_R_INFO(s->dynid, R_386_JMP_SLOT)); + + s->plt = plt->size - 16; + } else if(HEADTYPE == Hdarwin) { + // Same laziness as in 6l. + + Sym *plt; + + plt = lookup(".plt", 0); + + addgotsym(s); + + adduint32(lookup(".linkedit.plt", 0), s->dynid); + + // jmpq *got+size(IP) + s->plt = plt->size; + + adduint8(plt, 0xff); + adduint8(plt, 0x25); + addaddrplus(plt, lookup(".got", 0), s->got); + } else { + diag("addpltsym: unsupported binary format"); + } +} + +static void +addgotsym(Sym *s) +{ + Sym *got, *rel; + + if(s->got >= 0) + return; + + adddynsym(s); + got = lookup(".got", 0); + s->got = got->size; + adduint32(got, 0); + + if(iself) { + rel = lookup(".rel", 0); + addaddrplus(rel, got, s->got); + adduint32(rel, ELF32_R_INFO(s->dynid, R_386_GLOB_DAT)); + } else if(HEADTYPE == Hdarwin) { + adduint32(lookup(".linkedit.got", 0), s->dynid); + } else { + diag("addgotsym: unsupported binary format"); + } } void -wput(ushort w) +adddynsym(Sym *s) { - cput(w>>8); - cput(w); + Sym *d, *str; + int t; + char *name; + + if(s->dynid >= 0) + return; + + if(s->dynimpname == nil) + diag("adddynsym: no dynamic name for %s", s->name); + + if(iself) { + s->dynid = nelfsym++; + + d = lookup(".dynsym", 0); + + /* name */ + name = s->dynimpname; + if(name == nil) + name = s->name; + adduint32(d, addstring(lookup(".dynstr", 0), name)); + + /* value */ + if(s->type == SDYNIMPORT) + adduint32(d, 0); + else + addaddr(d, s); + + /* size */ + adduint32(d, 0); + + /* type */ + t = STB_GLOBAL << 4; + if(s->dynexport && s->type == STEXT) + t |= STT_FUNC; + else + t |= STT_OBJECT; + adduint8(d, t); + adduint8(d, 0); + + /* shndx */ + if(!s->dynexport && s->dynimpname != nil) + adduint16(d, SHN_UNDEF); + else { + switch(s->type) { + default: + case STEXT: + t = 11; + break; + case SRODATA: + t = 12; + break; + case SDATA: + t = 13; + break; + case SBSS: + t = 14; + break; + } + adduint16(d, t); + } + } else if(HEADTYPE == Hdarwin) { + // Mach-O symbol nlist32 + d = lookup(".dynsym", 0); + name = s->dynimpname; + if(name == nil) + name = s->name; + s->dynid = d->size/12; + // darwin still puts _ prefixes on all C symbols + str = lookup(".dynstr", 0); + adduint32(d, str->size); + adduint8(str, '_'); + addstring(str, name); + adduint8(d, 0x01); // type - N_EXT - external symbol + adduint8(d, 0); // section + adduint16(d, 0); // desc + adduint32(d, 0); // value + } else if(HEADTYPE != Hwindows) { + diag("adddynsym: unsupported binary format"); + } } void -lput(long l) +adddynlib(char *lib) { - cput(l>>24); - cput(l>>16); - cput(l>>8); - cput(l); + Sym *s; + + if(!needlib(lib)) + return; + + if(iself) { + s = lookup(".dynstr", 0); + if(s->size == 0) + addstring(s, ""); + elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib)); + } else if(HEADTYPE == Hdarwin) { + machoadddynlib(lib); + } else if(HEADTYPE != Hwindows) { + diag("adddynlib: unsupported binary format"); + } } void -lputl(long l) +doelf(void) { - cput(l); - cput(l>>8); - cput(l>>16); - cput(l>>24); + Sym *s, *shstrtab, *dynstr; + + if(!iself) + return; + + /* predefine strings we need for section headers */ + shstrtab = lookup(".shstrtab", 0); + shstrtab->type = SELFROSECT; + shstrtab->reachable = 1; + + elfstr[ElfStrEmpty] = addstring(shstrtab, ""); + elfstr[ElfStrText] = addstring(shstrtab, ".text"); + elfstr[ElfStrData] = addstring(shstrtab, ".data"); + elfstr[ElfStrBss] = addstring(shstrtab, ".bss"); + addstring(shstrtab, ".elfdata"); + addstring(shstrtab, ".rodata"); + addstring(shstrtab, ".gosymtab"); + addstring(shstrtab, ".gopclntab"); + if(!debug['s']) { + elfstr[ElfStrSymtab] = addstring(shstrtab, ".symtab"); + elfstr[ElfStrStrtab] = addstring(shstrtab, ".strtab"); + dwarfaddshstrings(shstrtab); + } + 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"); + elfstr[ElfStrRelPlt] = addstring(shstrtab, ".rel.plt"); + elfstr[ElfStrPlt] = addstring(shstrtab, ".plt"); + elfstr[ElfStrGnuVersion] = addstring(shstrtab, ".gnu.version"); + elfstr[ElfStrGnuVersionR] = addstring(shstrtab, ".gnu.version_r"); + + /* dynamic symbol table - first entry all zeros */ + s = lookup(".dynsym", 0); + s->type = SELFROSECT; + s->reachable = 1; + s->size += ELF32SYMSIZE; + + /* dynamic string table */ + s = lookup(".dynstr", 0); + s->reachable = 1; + s->type = SELFROSECT; + if(s->size == 0) + addstring(s, ""); + dynstr = s; + + /* relocation table */ + s = lookup(".rel", 0); + s->reachable = 1; + s->type = SELFROSECT; + + /* global offset table */ + s = lookup(".got", 0); + s->reachable = 1; + s->type = SELFSECT; // writable + + /* hash */ + s = lookup(".hash", 0); + s->reachable = 1; + s->type = SELFROSECT; + + /* got.plt */ + s = lookup(".got.plt", 0); + s->reachable = 1; + s->type = SELFSECT; // writable + + s = lookup(".plt", 0); + s->reachable = 1; + s->type = SELFROSECT; + + s = lookup(".rel.plt", 0); + s->reachable = 1; + s->type = SELFROSECT; + + s = lookup(".gnu.version", 0); + s->reachable = 1; + s->type = SELFROSECT; + + s = lookup(".gnu.version_r", 0); + s->reachable = 1; + s->type = SELFROSECT; + + elfsetupplt(); + + /* define dynamic elf table */ + s = lookup(".dynamic", 0); + s->reachable = 1; + s->type = SELFSECT; // writable + + /* + * .dynamic table + */ + 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); + if(rpath) + elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath)); + elfwritedynentsym(s, DT_PLTGOT, lookup(".got.plt", 0)); + elfwritedynent(s, DT_PLTREL, DT_REL); + elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rel.plt", 0)); + elfwritedynentsym(s, DT_JMPREL, lookup(".rel.plt", 0)); + + elfwritedynent(s, DT_DEBUG, 0); + + // Do not write DT_NULL. elfdynhash will finish it. + } } void -strnput(char *s, int n) +shsym(Elf64_Shdr *sh, Sym *s) { - for(; *s && n > 0; s++){ - cput(*s); - n--; - } - while(n > 0){ - cput(0); - n--; - } + vlong addr; + addr = symaddr(s); + if(sh->flags&SHF_ALLOC) + sh->addr = addr; + sh->off = datoff(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; - long v, magic; - int a; - uchar *op1; + int32 v, magic; + int a, dynsym; + uint32 symo, startva, dwarfoff, machlink; + ElfEhdr *eh; + ElfPhdr *ph, *pph; + ElfShdr *sh; + Section *sect; + Sym *sym; + int o; + int i; 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; - if(p->pc != pc) { - if(!debug['a']) - print("%P\n", curp); - diag("phase error %lux sb %lux in %s", p->pc, pc, TNAME); - pc = p->pc; - } - curp = p; - asmins(p); - 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; - } - cflush(); - switch(HEADTYPE) { - default: - diag("unknown header type %ld", 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: - case 5: - seek(cout, HEADR+textsize, 0); - break; - case 3: - case 4: - seek(cout, HEADR+rnd(textsize, INITRND), 0); - break; + sect = segtext.sect; + cseek(sect->vaddr - segtext.vaddr + segtext.fileoff); + codeblk(sect->vaddr, sect->len); + + /* output read-only data in text segment (rodata, gosymtab and pclntab) */ + for(sect = sect->next; sect != nil; sect = sect->next) { + cseek(sect->vaddr - segtext.vaddr + segtext.fileoff); + datblk(sect->vaddr, sect->len); } if(debug['v']) Bprint(&bso, "%5.2f datblk\n", cputime()); Bflush(&bso); - if(dlm){ - char buf[8]; + cseek(segdata.fileoff); + datblk(segdata.vaddr, segdata.filelen); - write(cout, buf, INITDAT-textsize); - textsize = INITDAT; + machlink = 0; + if(HEADTYPE == Hdarwin) { + if(debug['v']) + Bprint(&bso, "%5.2f dwarf\n", cputime()); + + dwarfoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen, INITRND); + cseek(dwarfoff); + + segdwarf.fileoff = cpos(); + dwarfemitdebugsections(); + segdwarf.filelen = cpos() - segdwarf.fileoff; + + machlink = domacholink(); } - 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); + if(iself) { + /* index of elf text section; needed by asmelfsym, double-checked below */ + /* !debug['d'] causes extra sections before the .text section */ + elftextsh = 2; + if(!debug['d']) { + elftextsh += 10; + if(elfverneed) + elftextsh += 2; + } } symsize = 0; spsize = 0; lcsize = 0; + symo = 0; if(!debug['s']) { + // TODO: rationalize 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); + if(iself) + goto Elfsym; + case Hgarbunix: + symo = rnd(HEADR+segtext.filelen, 8192)+segdata.filelen; break; - case 1: - seek(cout, rnd(HEADR+textsize, INITRND)+datsize, 0); + case Hunixcoff: + symo = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen; break; - case 2: - case 5: - seek(cout, HEADR+textsize+datsize, 0); + case Hplan9x32: + symo = HEADR+segtext.filelen+segdata.filelen; break; - case 3: - case 4: + case Hmsdoscom: + case Hmsdosexe: debug['s'] = 1; + symo = HEADR+segtext.filelen+segdata.filelen; + break; + case Hdarwin: + symo = rnd(HEADR+segtext.filelen, INITRND)+rnd(segdata.filelen, INITRND)+machlink; + break; + Elfsym: + symo = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen; + symo = rnd(symo, INITRND); + break; + case Hwindows: + symo = rnd(HEADR+segtext.filelen, PEFILEALIGN)+segdata.filelen; + symo = rnd(symo, PEFILEALIGN); break; } - 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(); - } - else if(dlm){ - seek(cout, HEADR+textsize+datsize, 0); - asmdyn(); - cflush(); + cseek(symo); + switch(HEADTYPE) { + default: + if(iself) { + if(debug['v']) + Bprint(&bso, "%5.2f elfsym\n", cputime()); + asmelfsym(); + cflush(); + cwrite(elfstrdat, elfstrsize); + + if(debug['v']) + Bprint(&bso, "%5.2f dwarf\n", cputime()); + dwarfemitdebugsections(); + } + break; + case Hplan9x32: + asmplan9sym(); + cflush(); + + sym = lookup("pclntab", 0); + if(sym != nil) { + lcsize = sym->np; + for(i=0; i < lcsize; i++) + cput(sym->p[i]); + + cflush(); + } + break; + case Hwindows: + if(debug['v']) + Bprint(&bso, "%5.2f dwarf\n", cputime()); + dwarfemitdebugsections(); + break; + } } if(debug['v']) Bprint(&bso, "%5.2f headr\n", cputime()); Bflush(&bso); - seek(cout, 0L, 0); + cseek(0L); 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 ?? */ + if(iself) + goto Elfput; + case Hgarbunix: /* garbage */ + lputb(0x160L<<16); /* magic and sections */ + lputb(0L); /* time and date */ + lputb(rnd(HEADR+segtext.filelen, 4096)+segdata.filelen); + lputb(symsize); /* nsyms */ + lputb((0x38L<<16)|7L); /* size of optional hdr and flags */ + lputb((0413<<16)|0437L); /* magic and version */ + lputb(rnd(HEADR+segtext.filelen, 4096)); /* sizes */ + lputb(segdata.filelen); + lputb(segdata.len - segdata.filelen); + lputb(entryvalue()); /* va of entry */ + lputb(INITTEXT-HEADR); /* va of base of text */ + lputb(segdata.vaddr); /* va of base of data */ + lputb(segdata.vaddr+segdata.filelen); /* va of base of bss */ + lputb(~0L); /* gp reg mask */ + lputb(0L); + lputb(0L); + lputb(0L); + lputb(0L); + lputb(~0L); /* gp value ?? */ break; - case 1: /* unix coff */ + case Hunixcoff: /* unix coff */ /* * file header */ @@ -241,19 +832,19 @@ * 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(rnd(segtext.filelen, INITRND)); /* text sizes */ + lputl(segdata.filelen); /* data sizes */ + lputl(segdata.len - segdata.filelen); /* bss sizes */ + lputb(entryvalue()); /* va of entry */ lputl(INITTEXT); /* text start */ - lputl(INITDAT); /* data start */ + lputl(segdata.vaddr); /* data start */ /* * text section header */ - strnput(".text", 8); + s8put(".text"); lputl(HEADR); /* pa */ lputl(HEADR); /* va */ - lputl(textsize); /* text size */ + lputl(segtext.filelen); /* text size */ lputl(HEADR); /* file offset */ lputl(0); /* relocation */ lputl(0); /* line numbers */ @@ -262,11 +853,11 @@ /* * data section header */ - strnput(".data", 8); - lputl(INITDAT); /* pa */ - lputl(INITDAT); /* va */ - lputl(datsize); /* data size */ - lputl(HEADR+textsize); /* file offset */ + s8put(".data"); + lputl(segdata.vaddr); /* pa */ + lputl(segdata.vaddr); /* va */ + lputl(segdata.filelen); /* data size */ + lputl(HEADR+segtext.filelen); /* file offset */ lputl(0); /* relocation */ lputl(0); /* line numbers */ lputl(0); /* relocation, line numbers */ @@ -274,10 +865,10 @@ /* * bss section header */ - strnput(".bss", 8); - lputl(INITDAT+datsize); /* pa */ - lputl(INITDAT+datsize); /* va */ - lputl(bsssize); /* bss size */ + s8put(".bss"); + lputl(segdata.vaddr+segdata.filelen); /* pa */ + lputl(segdata.vaddr+segdata.filelen); /* va */ + lputl(segdata.len - segdata.filelen); /* bss size */ lputl(0); /* file offset */ lputl(0); /* relocation */ lputl(0); /* line numbers */ @@ -286,35 +877,33 @@ /* * comment section header */ - strnput(".comment", 8); + 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(HEADR+segtext.filelen+segdata.filelen); /* file offset */ + lputl(HEADR+segtext.filelen+segdata.filelen); /* offset of syms */ + lputl(HEADR+segtext.filelen+segdata.filelen+symsize);/* offset of line numbers */ lputl(0); /* relocation, line numbers */ lputl(0x200); /* flags comment only */ break; - case 2: /* plan9 */ + case Hplan9x32: /* 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 */ + lputb(magic); /* magic */ + lputb(segtext.filelen); /* sizes */ + lputb(segdata.filelen); + lputb(segdata.len - segdata.filelen); + lputb(symsize); /* nsyms */ + lputb(entryvalue()); /* va of entry */ + lputb(spsize); /* sp offsets */ + lputb(lcsize); /* line offsets */ break; - case 3: + case Hmsdoscom: /* MS-DOS .COM */ break; - case 4: + case Hmsdosexe: /* fake MS-DOS .EXE */ - v = rnd(HEADR+textsize, INITRND)+datsize; + v = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen; wputl(0x5A4D); /* 'MZ' */ wputl(v % 512); /* bytes in last page */ wputl(rnd(v, 512)/512); /* total number of pages */ @@ -334,214 +923,270 @@ wputl(0x003E); /* reloc table offset */ wputl(0x0000); /* overlay number */ break; - case 5: - strnput("\177ELF", 4); /* e_ident */ - cput(1); /* class = 32 bit */ - cput(1); /* data = LSB */ - cput(1); /* version = CURRENT */ - strnput("", 9); - wputl(2); /* type = EXEC */ - wputl(3); /* machine = 386 */ - lputl(1L); /* version = CURRENT */ - lputl(PADDR(entryvalue())); /* entry vaddr */ - lputl(52L); /* offset to first phdr */ - lputl(0L); /* offset to first shdr */ - lputl(0L); /* flags = 386 */ - wputl(52); /* Ehdr size */ - wputl(32); /* Phdr size */ - wputl(3); /* # of Phdrs */ - wputl(0); /* Shdr size */ - wputl(0); /* # of Shdrs */ - wputl(0); /* Shdr string size */ - lputl(1L); /* text - type = PT_LOAD */ - lputl(HEADR); /* file offset */ - lputl(INITTEXT); /* vaddr */ - lputl(PADDR(INITTEXT)); /* paddr */ - lputl(textsize); /* file size */ - lputl(textsize); /* memory size */ - lputl(0x05L); /* protections = RX */ - lputl(INITRND); /* alignment */ + case Hdarwin: + asmbmacho(); + break; - lputl(1L); /* data - type = PT_LOAD */ - lputl(HEADR+textsize); /* file offset */ - lputl(INITDAT); /* vaddr */ - lputl(PADDR(INITDAT)); /* paddr */ - lputl(datsize); /* file size */ - lputl(datsize+bsssize); /* memory size */ - lputl(0x06L); /* protections = RW */ - lputl(INITRND); /* alignment */ + Elfput: + eh = getElfEhdr(); + startva = INITTEXT - HEADR; - lputl(0L); /* data - type = PT_NULL */ - lputl(HEADR+textsize+datsize); /* file offset */ - lputl(0L); - lputl(0L); - lputl(symsize); /* symbol table size */ - lputl(lcsize); /* line number size */ - lputl(0x04L); /* protections = R */ - lputl(0x04L); /* alignment */ + /* This null SHdr must appear before all others */ + newElfShdr(elfstr[ElfStrEmpty]); + + /* program header info */ + 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; + + /* + * PHDR must be in a loaded segment. Adjust the text + * segment boundaries downwards to include it. + */ + o = segtext.vaddr - pph->vaddr; + segtext.vaddr -= o; + segtext.len += o; + o = segtext.fileoff - pph->off; + segtext.fileoff -= o; + segtext.filelen += o; + + if(!debug['d']) { + /* interpreter */ + sh = newElfShdr(elfstr[ElfStrInterp]); + sh->type = SHT_PROGBITS; + sh->flags = SHF_ALLOC; + sh->addralign = 1; + if(interpreter == nil) { + switch(HEADTYPE) { + case Hlinux: + interpreter = linuxdynld; + break; + case Hfreebsd: + interpreter = freebsddynld; + break; + case Hopenbsd: + interpreter = openbsddynld; + break; + } + } + elfinterp(sh, startva, interpreter); + + ph = newElfPhdr(); + ph->type = PT_INTERP; + ph->flags = PF_R; + phsh(ph, sh); + } + + elfphload(&segtext); + elfphload(&segdata); + + /* 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)); + + if(elfverneed) { + sh = newElfShdr(elfstr[ElfStrGnuVersion]); + sh->type = SHT_GNU_VERSYM; + sh->flags = SHF_ALLOC; + sh->addralign = 2; + sh->link = dynsym; + sh->entsize = 2; + shsym(sh, lookup(".gnu.version", 0)); + + sh = newElfShdr(elfstr[ElfStrGnuVersionR]); + sh->type = SHT_GNU_VERNEED; + sh->flags = SHF_ALLOC; + sh->addralign = 4; + sh->info = elfverneed; + sh->link = dynsym+1; // dynstr + shsym(sh, lookup(".gnu.version_r", 0)); + } + + sh = newElfShdr(elfstr[ElfStrRelPlt]); + sh->type = SHT_REL; + sh->flags = SHF_ALLOC; + sh->entsize = ELF32RELSIZE; + sh->addralign = 4; + sh->link = dynsym; + sh->info = eh->shnum; // .plt + shsym(sh, lookup(".rel.plt", 0)); + + sh = newElfShdr(elfstr[ElfStrPlt]); + sh->type = SHT_PROGBITS; + sh->flags = SHF_ALLOC+SHF_EXECINSTR; + sh->entsize = 4; + sh->addralign = 4; + shsym(sh, lookup(".plt", 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; + + sh = newElfShstrtab(elfstr[ElfStrShstrtab]); + sh->type = SHT_STRTAB; + sh->addralign = 1; + shsym(sh, lookup(".shstrtab", 0)); + + if(elftextsh != eh->shnum) + diag("elftextsh = %d, want %d", elftextsh, eh->shnum); + for(sect=segtext.sect; sect!=nil; sect=sect->next) + elfshbits(sect); + for(sect=segdata.sect; sect!=nil; sect=sect->next) + elfshbits(sect); + + if (!debug['s']) { + sh = newElfShdr(elfstr[ElfStrSymtab]); + sh->type = SHT_SYMTAB; + sh->off = symo; + sh->size = symsize; + sh->addralign = 4; + sh->entsize = 16; + sh->link = eh->shnum; // link to strtab + + sh = newElfShdr(elfstr[ElfStrStrtab]); + sh->type = SHT_STRTAB; + sh->off = symo+symsize; + sh->size = elfstrsize; + sh->addralign = 1; + + dwarfaddelfheaders(); + } + + /* 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 Hfreebsd: + eh->ident[EI_OSABI] = ELFOSABI_FREEBSD; + break; + case Hopenbsd: + eh->ident[EI_OSABI] = ELFOSABI_OPENBSD; + 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; + } + + cseek(0); + a = 0; + a += elfwritehdr(); + a += elfwritephdrs(); + a += elfwriteshdrs(); + a += elfwriteinterp(); + if(a > ELFRESERVE) + diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE); + break; + + case Hwindows: + asmbpe(); break; } cflush(); } void -cflush(void) +s8put(char *n) { - int n; + char name[8]; + int i; - n = sizeof(buf.cbuf) - cbc; - if(n) - write(cout, buf.cbuf, n); - cbp = buf.cbuf; - cbc = sizeof(buf.cbuf); + strncpy(name, n, sizeof(name)); + for(i=0; ilink) { - curp = p; - l = p->from.sym->value + p->from.offset - s; - c = p->from.scale; - i = 0; - if(l < 0) { - if(l+c <= 0) - continue; - while(l < 0) { - l++; - i++; - } - } - if(l >= n) - 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; - if(debug['a'] && i == 0) { - Bprint(&bso, pcstr, l+s+INITDAT); - for(j=0; jto.ieee; - if(debug['a'] && i == 0) { - Bprint(&bso, pcstr, l+s+INITDAT); - for(j=0; jto.scon[j] & 0xff); - Bprint(&bso, "\t%P\n", curp); - } - for(; ito.scon[i]; - l++; - } - break; - default: - fl = p->to.offset; - 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: - if(debug['a'] && i == 0) { - Bprint(&bso, pcstr, l+s+INITDAT); - for(j=0; jtype == STEXT) + put(s, s->name, 'T', s->value, s->size, s->version, 0); + + for(h=0; hhash) { + if(s->hide) + continue; + switch(s->type&~SSUB) { + case SCONST: + case SRODATA: + case SDATA: + case SELFROSECT: + case SMACHO: + case SMACHOGOT: + case STYPE: + case SSTRING: + case SGOSTRING: + case SWINDOWS: + if(!s->reachable) + continue; + put(s, s->name, 'D', symaddr(s), s->size, s->version, s->gotype); + continue; + + case SBSS: + if(!s->reachable) + continue; + put(s, s->name, 'B', symaddr(s), s->size, s->version, s->gotype); + continue; + + case SFILE: + put(nil, s->name, 'f', s->value, 0, s->version, 0); + continue; + } + } + } + + for(s = textp; s != nil; s = s->next) { + if(s->text == nil) + continue; + + /* filenames first */ + for(a=s->autom; a; a=a->link) + if(a->type == D_FILE) + put(nil, a->asym->name, 'z', a->aoffset, 0, 0, 0); + else + if(a->type == D_FILE1) + put(nil, a->asym->name, 'Z', a->aoffset, 0, 0, 0); + + put(s, s->name, 'T', s->value, s->size, s->version, s->gotype); + + /* frame, auto and param after */ + put(nil, ".frame", 'm', s->text->to.offset+4, 0, 0, 0); + + for(a=s->autom; a; a=a->link) + if(a->type == D_AUTO) + put(nil, a->asym->name, 'a', -a->aoffset, 0, 0, a->gotype); + else + if(a->type == D_PARAM) + put(nil, a->asym->name, 'p', a->aoffset, 0, 0, a->gotype); + } + if(debug['v'] || debug['n']) + Bprint(&bso, "symsize = %d\n", symsize); + Bflush(&bso); +} diff -r d8d00747375b sys/src/cmd/8l/compat.c --- a/sys/src/cmd/8l/compat.c Thu Sep 29 03:00:00 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -#include "l.h" - -/* - * fake malloc - */ -void* -malloc(ulong n) -{ - void *p; - - while(n & 7) - n++; - while(nhunk < n) - gethunk(); - p = hunk; - nhunk -= n; - hunk += n; - return p; -} - -void -free(void *p) -{ - USED(p); -} - -void* -calloc(ulong m, ulong n) -{ - void *p; - - n *= m; - p = malloc(n); - memset(p, 0, n); - return p; -} - -void* -realloc(void*, ulong) -{ - fprint(2, "realloc called\n"); - abort(); - return 0; -} - -void* -mysbrk(ulong size) -{ - return sbrk(size); -} - -void -setmalloctag(void *v, ulong pc) -{ - USED(v, pc); -} diff -r d8d00747375b sys/src/cmd/8l/l.h --- a/sys/src/cmd/8l/l.h Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/8l/l.h Mon Nov 14 17:35:25 2011 +0100 @@ -1,88 +1,161 @@ +// Inferno utils/8l/l.h +// http://code.google.com/p/inferno-os/source/browse/utils/8l/l.h +// +// 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 #include #include -#include "../8c/8.out.h" +#include "8.out.h" #ifndef EXTERN #define EXTERN extern #endif +enum +{ + thechar = '8', + PtrSize = 4 +}; + #define P ((Prog*)0) #define S ((Sym*)0) -#define TNAME (curtext?curtext->from.sym->name:noname) - -#define cput(c)\ - { *cbp++ = c;\ - if(--cbc <= 0)\ - cflush(); } +#define TNAME (cursym?cursym->name:noname) typedef struct Adr Adr; typedef struct Prog Prog; typedef struct Sym Sym; typedef struct Auto Auto; typedef struct Optab Optab; +typedef struct Reloc Reloc; struct Adr { union { - long u0offset; + int32 u0offset; char u0scon[8]; Prog *u0cond; /* not used, but should be D_BRANCH */ Ieee u0ieee; + char *u0sbig; } u0; - union - { - Auto* u1autom; - Sym* u1sym; - } u1; + Sym* sym; short type; - char index; + uchar index; char scale; + int32 offset2; }; #define offset u0.u0offset #define scon u0.u0scon #define cond u0.u0cond #define ieee u0.u0ieee +#define sbig u0.u0sbig -#define autom u1.u1autom -#define sym u1.u1sym +struct Reloc +{ + int32 off; + uchar siz; + int32 type; + int32 add; + Sym* sym; +}; struct Prog { Adr from; Adr to; - Prog *forwd; + Prog* forwd; + Prog* comefrom; Prog* link; Prog* pcond; /* work on this */ - long pc; - long line; + int32 pc; + int32 spadj; + int32 line; + short as; + char width; /* fake for DATA */ + char ft; /* oclass cache */ + char tt; uchar mark; /* work on these */ uchar back; + uchar bigjmp; +}; +#define datasize from.scale +#define textflag from.scale +#define iscall(p) ((p)->as == ACALL) - short as; - char width; /* fake for DATA */ -}; struct Auto { Sym* asym; Auto* link; - long aoffset; + int32 aoffset; short type; + Sym* gotype; }; struct Sym { - char *name; + char* name; short type; short version; - short become; - short frame; - uchar subtype; - ushort file; - long value; - long sig; - Sym* link; + uchar dupok; + uchar reachable; + uchar dynexport; + uchar special; + uchar stkcheck; + uchar hide; + int32 value; + int32 size; + int32 sig; + int32 dynid; + int32 plt; + int32 got; + Sym* hash; // in hash table + Sym* allsym; // in all symbol list + Sym* next; // in text or data list + Sym* sub; // in sub list + Sym* outer; // container of sub + Sym* gotype; + char* file; + char* dynimpname; + char* dynimplib; + char* dynimpvers; + + // STEXT + Auto* autom; + Prog* text; + + // SDATA, SBSS + uchar* p; + int32 np; + int32 maxp; + Reloc* r; + int32 nr; + int32 maxr; }; struct Optab { @@ -94,20 +167,6 @@ enum { - STEXT = 1, - SDATA, - SBSS, - SDATA1, - SXREF, - SFILE, - SCONST, - SUNDEF, - - SIMPORT, - SEXPORT, - - NHASH = 10007, - NHUNK = 100000, MINSIZ = 4, STRINGSZ = 200, MINLC = 1, @@ -149,6 +208,8 @@ Z_rp, Zbr, Zcall, + Zcallcon, + Zcallind, Zib_, Zib_rp, Zibo_m, @@ -156,6 +217,7 @@ Zil_rp, Zilo_m, Zjmp, + Zjmpcon, Zloop, Zm_o, Zm_r, @@ -180,168 +242,134 @@ Pm = 0x0f, /* 2byte opcode escape */ Pq = 0xff, /* both escape */ Pb = 0xfe, /* byte operands */ - - Roffset = 22, /* no. bits for offset in relocation address */ - Rindex = 10, /* no. bits for index in relocation address */ }; -EXTERN union -{ - struct - { - char obuf[MAXIO]; /* output buffer */ - uchar ibuf[MAXIO]; /* input buffer */ - } u; - char dbuf[1]; -} buf; - -#define cbuf u.obuf -#define xbuf u.ibuf - #pragma varargck type "A" int -#pragma varargck type "A" uint #pragma varargck type "D" Adr* +#pragma varargck type "I" uchar* #pragma varargck type "P" Prog* #pragma varargck type "R" int #pragma varargck type "S" char* +#pragma varargck type "Y" Sym* +#pragma varargck type "Z" char* +#pragma varargck type "i" char* -#pragma varargck argpos diag 1 - -EXTERN long HEADR; -EXTERN long HEADTYPE; -EXTERN long INITDAT; -EXTERN long INITRND; -EXTERN long INITTEXT; +EXTERN int32 HEADR; +EXTERN int32 HEADTYPE; +EXTERN int32 INITRND; +EXTERN int32 INITTEXT; +EXTERN int32 INITDAT; EXTERN char* INITENTRY; /* entry point */ -EXTERN Biobuf bso; -EXTERN long bsssize; -EXTERN long casepc; -EXTERN int cbc; -EXTERN char* cbp; +EXTERN int32 casepc; EXTERN char* pcstr; -EXTERN int cout; EXTERN Auto* curauto; EXTERN Auto* curhist; EXTERN Prog* curp; -EXTERN Prog* curtext; -EXTERN Prog* datap; -EXTERN Prog* edatap; -EXTERN long datsize; +EXTERN Sym* cursym; +EXTERN Sym* datap; +EXTERN int32 elfdatsize; EXTERN char debug[128]; EXTERN char literal[32]; -EXTERN Prog* etextp; +EXTERN Sym* etextp; EXTERN Prog* firstp; -EXTERN char fnuxi8[8]; -EXTERN char fnuxi4[4]; -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* hunk; -EXTERN char inuxi1[1]; -EXTERN char inuxi2[2]; -EXTERN char inuxi4[4]; -EXTERN char ycover[Ymax*Ymax]; +EXTERN uchar ycover[Ymax*Ymax]; EXTERN uchar* andptr; -EXTERN uchar and[30]; +EXTERN uchar and[100]; EXTERN char reg[D_NONE]; -EXTERN Prog* lastp; -EXTERN long lcsize; +EXTERN int32 lcsize; +EXTERN int maxop; EXTERN int nerrors; -EXTERN long nhunk; -EXTERN long nsymbol; EXTERN char* noname; -EXTERN char* outfile; -EXTERN long pc; -EXTERN long spsize; +EXTERN int32 pc; +EXTERN char* interpreter; +EXTERN char* rpath; +EXTERN int32 spsize; EXTERN Sym* symlist; -EXTERN long symsize; -EXTERN Prog* textp; -EXTERN long textsize; -EXTERN long thunk; +EXTERN int32 symsize; +EXTERN Sym* textp; +EXTERN int32 textsize; EXTERN int version; EXTERN Prog zprg; EXTERN int dtype; - -EXTERN Adr* reloca; -EXTERN int doexp, dlm; -EXTERN int imports, nimports; -EXTERN int exports, nexports; -EXTERN char* EXPTAB; -EXTERN Prog undefp; - -#define UP (&undefp) +EXTERN int tlsoffset; +EXTERN Sym* adrgotype; // type symbol on last Adr read +EXTERN Sym* fromgotype; // type symbol on last p->from read +EXTERN int elftextsh; extern Optab optab[]; extern char* anames[]; int Aconv(Fmt*); int Dconv(Fmt*); +int Iconv(Fmt*); int Pconv(Fmt*); int Rconv(Fmt*); int Sconv(Fmt*); -void addhist(long, int); +void addhist(int32, int); Prog* appendp(Prog*); void asmb(void); void asmdyn(void); void asmins(Prog*); -void asmlc(void); -void asmsp(void); void asmsym(void); -long atolwhex(char*); +int32 atolwhex(char*); Prog* brchain(Prog*); Prog* brloop(Prog*); void cflush(void); -void ckoff(Sym*, long); Prog* copyp(Prog*); +vlong cpos(void); double cputime(void); -void datblk(long, long); void diag(char*, ...); void dodata(void); -void doinit(void); +void doelf(void); void doprof1(void); void doprof2(void); void dostkoff(void); -void dynreloc(Sym*, ulong, int); -long entryvalue(void); -void errorexit(void); -void export(void); -int find1(long, int); -int find2(long, int); +int32 entryvalue(void); void follow(void); -void gethunk(void); -void histtoauto(void); -double ieeedtod(Ieee*); -long ieeedtof(Ieee*); -void import(void); -void ldobj(int, long, char*); -void loadlib(void); +void instinit(void); void listinit(void); Sym* lookup(char*, int); -void lput(long); -void lputl(long); +void lputb(int32); +void lputl(int32); +void vputl(uint64); +void strnput(char*, int); void main(int, char*[]); -void mkfwd(void); -void* mysbrk(ulong); -void nuxiinit(void); -void objfile(char*); +void* mal(uint32); int opsize(Prog*); void patch(void); Prog* prg(void); -void readundefs(char*, int); int relinv(int); -long reuse(Prog*, Sym*); -long rnd(long, long); +int32 rnd(int32, int32); +void s8put(char*); void span(void); void undef(void); -void undefsym(Sym*); -long vaddr(Adr*); +int32 symaddr(Sym*); void wput(ushort); -void xdefine(char*, int, long); -void xfol(Prog*); -int zaddr(uchar*, Adr*, Sym*[]); -void zerosig(char*); +void wputl(ushort); +void xdefine(char*, int, int32); + +uint32 machheadr(void); +vlong addaddr(Sym *s, Sym *t); +vlong addsize(Sym *s, Sym *t); +vlong addstring(Sym *s, char *str); +vlong adduint16(Sym *s, uint16 v); +vlong adduint32(Sym *s, uint32 v); +vlong adduint64(Sym *s, uint64 v); +vlong adduint8(Sym *s, uint8 v); +vlong adduintxx(Sym *s, uint64 v, int wid); + +/* + * go.c + */ +void deadcode(void); + +/* Native is little-endian */ +#define LPUT(a) lputl(a) +#define WPUT(a) wputl(a) +#define VPUT(a) vputl(a) + +/* Used by ../ld/dwarf.c */ +enum +{ + DWARFREGSP = 4 +}; diff -r d8d00747375b sys/src/cmd/8l/list.c --- a/sys/src/cmd/8l/list.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/8l/list.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,4 +1,37 @@ +// Inferno utils/8l/list.c +// http://code.google.com/p/inferno-os/source/browse/utils/8l/list.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. + +// Printing. + #include "l.h" +#include "../ld/lib.h" void listinit(void) @@ -9,6 +42,7 @@ fmtinstall('D', Dconv); fmtinstall('S', Sconv); fmtinstall('P', Pconv); + fmtinstall('I', Iconv); } static Prog *bigP; @@ -16,7 +50,6 @@ int Pconv(Fmt *fp) { - char str[STRINGSZ]; Prog *p; p = va_arg(fp->args, Prog*); @@ -24,23 +57,23 @@ switch(p->as) { case ATEXT: if(p->from.scale) { - sprint(str, "(%ld) %A %D,%d,%D", + fmtprint(fp, "(%d) %A %D,%d,%D", p->line, p->as, &p->from, p->from.scale, &p->to); break; } default: - sprint(str, "(%ld) %A %D,%D", + fmtprint(fp, "(%d) %A %D,%D", p->line, p->as, &p->from, &p->to); break; case ADATA: - case AINIT: - case ADYNT: - sprint(str, "(%ld) %A %D/%d,%D", + case AINIT_: + case ADYNT_: + fmtprint(fp, "(%d) %A %D/%d,%D", p->line, p->as, &p->from, p->from.scale, &p->to); break; } bigP = P; - return fmtstrcpy(fp, str); + return 0; } int @@ -52,26 +85,34 @@ return fmtstrcpy(fp, anames[i]); } +char* +xsymname(Sym *s) +{ + if(s == nil) + return "!!noname!!"; + return s->name; +} + int Dconv(Fmt *fp) { - char str[40], s[20]; + char str[STRINGSZ], s[STRINGSZ]; Adr *a; int i; a = va_arg(fp->args, Adr*); i = a->type; - if(i >= D_INDIR) { + if(i >= D_INDIR && i < 2*D_INDIR) { if(a->offset) - sprint(str, "%ld(%R)", a->offset, i-D_INDIR); + snprint(str, sizeof str, "%d(%R)", a->offset, i-D_INDIR); else - sprint(str, "(%R)", i-D_INDIR); + snprint(str, sizeof str, "(%R)", i-D_INDIR); goto brk; } switch(i) { default: - sprint(str, "%R", i); + snprint(str, sizeof str, "%R", i); break; case D_NONE: @@ -81,61 +122,68 @@ case D_BRANCH: if(bigP != P && bigP->pcond != P) if(a->sym != S) - sprint(str, "%lux+%s", bigP->pcond->pc, + snprint(str, sizeof str, "%ux+%s", bigP->pcond->pc, a->sym->name); else - sprint(str, "%lux", bigP->pcond->pc); + snprint(str, sizeof str, "%ux", bigP->pcond->pc); else - sprint(str, "%ld(PC)", a->offset); + snprint(str, sizeof str, "%d(PC)", a->offset); break; case D_EXTERN: - sprint(str, "%s+%ld(SB)", a->sym->name, a->offset); + snprint(str, sizeof str, "%s+%d(SB)", xsymname(a->sym), a->offset); break; case D_STATIC: - sprint(str, "%s<%d>+%ld(SB)", a->sym->name, + snprint(str, sizeof str, "%s<%d>+%d(SB)", xsymname(a->sym), a->sym->version, a->offset); break; case D_AUTO: - sprint(str, "%s+%ld(SP)", a->sym->name, a->offset); + snprint(str, sizeof str, "%s+%d(SP)", xsymname(a->sym), a->offset); break; case D_PARAM: if(a->sym) - sprint(str, "%s+%ld(FP)", a->sym->name, a->offset); + snprint(str, sizeof str, "%s+%d(FP)", a->sym->name, a->offset); else - sprint(str, "%ld(FP)", a->offset); + snprint(str, sizeof str, "%d(FP)", a->offset); break; case D_CONST: - sprint(str, "$%ld", a->offset); + snprint(str, sizeof str, "$%d", a->offset); + break; + + case D_CONST2: + snprint(str, sizeof str, "$%d-%d", a->offset, a->offset2); break; case D_FCONST: - sprint(str, "$(%.8lux,%.8lux)", a->ieee.h, a->ieee.l); + snprint(str, sizeof str, "$(%.8ux,%.8ux)", a->ieee.h, a->ieee.l); break; case D_SCONST: - sprint(str, "$\"%S\"", a->scon); + snprint(str, sizeof str, "$\"%S\"", a->scon); break; case D_ADDR: a->type = a->index; a->index = D_NONE; - sprint(str, "$%D", a); + snprint(str, sizeof str, "$%D", a); a->index = a->type; a->type = D_ADDR; goto conv; } brk: if(a->index != D_NONE) { - sprint(s, "(%R*%d)", a->index, a->scale); + sprint(s, "(%R*%d)", (int)a->index, a->scale); strcat(str, s); } conv: - return fmtstrcpy(fp, str); + fmtstrcpy(fp, str); +// if(a->gotype) +// fmtprint(fp, "«%s»", a->gotype->name); + return 0; } char* regstr[] = @@ -213,7 +261,7 @@ int Rconv(Fmt *fp) { - char str[20]; + char str[STRINGSZ]; int r; r = va_arg(fp->args, int); @@ -229,7 +277,7 @@ Sconv(Fmt *fp) { int i, c; - char str[30], *p, *a; + char str[STRINGSZ], *p, *a; a = va_arg(fp->args, char*); p = str; @@ -270,22 +318,51 @@ return fmtstrcpy(fp, str); } +int +Iconv(Fmt *fp) +{ + int i, n; + uchar *p; + char *s; + Fmt fmt; + + n = fp->prec; + fp->prec = 0; + if(!(fp->flags&FmtPrec) || n < 0) + return fmtstrcpy(fp, "%I"); + fp->flags &= ~FmtPrec; + p = va_arg(fp->args, uchar*); + + // format into temporary buffer and + // call fmtstrcpy to handle padding. + fmtstrinit(&fmt); + for(i=0; ifrom.sym != S) - tn = curtext->from.sym->name; + tn = ""; + sep = ""; + if(cursym != S) { + tn = cursym->name; + sep = ": "; + } va_start(arg, fmt); vseprint(buf, buf+sizeof(buf), fmt, arg); va_end(arg); - print("%s: %s\n", tn, buf); + print("%s%s%s\n", tn, sep, buf); nerrors++; - if(nerrors > 20 && !debug['A']) { + if(nerrors > 20) { print("too many errors\n"); errorexit(); } diff -r d8d00747375b sys/src/cmd/8l/mkenam --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/src/cmd/8l/mkenam Mon Nov 14 17:35:25 2011 +0100 @@ -0,0 +1,45 @@ +# Inferno utils/8c/mkenam +# http://code.google.com/p/inferno-os/source/browse/utils/8c/mkenam +# +# 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. + +awk ' +BEGIN { + print "char* anames[] =" + print "{" +} + +/^ A/ { + name=$1 + sub(/,/, "", name) + sub(/^A/, "", name) + print "\t\"" name "\"," +} + +END { print "};" } +' ../8l/8.out.h >enam.c diff -r d8d00747375b sys/src/cmd/8l/mkfile --- a/sys/src/cmd/8l/mkfile Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/8l/mkfile Mon Nov 14 17:35:25 2011 +0100 @@ -3,21 +3,35 @@ TARG=8l OFILES=\ asm.$O\ + data.$O\ + dwarf.$O\ + elf.$O\ + enam.$O\ + go.$O\ + ldelf.$O\ + ldmacho.$O\ + ldpe.$O\ + lib.$O\ + list.$O\ + macho.$O\ obj.$O\ optab.$O\ pass.$O\ + pe.$O\ + prof.$O\ span.$O\ - list.$O\ - enam.$O\ - compat.$O\ + symtab.$O\ HFILES=\ l.h\ - ../8c/8.out.h\ + ../8l/8.out.h\ + ../ld/dwarf.h\ + ../ld/elf.h\ + ../ld/lib.h\ + ../ld/macho.h\ BIN=/$objtype/bin CFILES=${OFILES:%.$O=%.c} -CFILES=${CFILES:enam.c=../8c/enam.c} UPDATE=\ mkfile\ $HFILES\ @@ -26,6 +40,9 @@ #ifndef DEFAULT @@ -7,125 +44,122 @@ #endif char *noname = ""; -char symname[] = SYMDEF; -char thechar = '8'; char *thestring = "386"; +Header headers[] = { + "garbunix", Hgarbunix, + "unixcoff", Hunixcoff, + "plan9", Hplan9x32, + "msdoscom", Hmsdoscom, + "msdosexe", Hmsdosexe, + "darwin", Hdarwin, + "linux", Hlinux, + "freebsd", Hfreebsd, + "openbsd", Hopenbsd, + "windows", Hwindows, + "windowsgui", Hwindows, + 0, 0 +}; + /* - * -H0 -T0x40004C -D0x10000000 is garbage unix - * -H1 -T0xd0 -R4 is unix coff - * -H2 -T4128 -R4096 is plan9 format - * -H3 -Tx -Rx is MS-DOS .COM - * -H4 -Tx -Rx is fake MS-DOS .EXE - * -H5 -T0x80100020 -R4096 is ELF + * -Hgarbunix -T0x40004C -D0x10000000 is garbage unix + * -Hunixcoff -T0xd0 -R4 is unix coff + * -Hplan9 -T4128 -R4096 is plan9 format + * -Hmsdoscom -Tx -Rx is MS-DOS .COM + * -Hmsdosexe -Tx -Rx is fake MS-DOS .EXE + * -Hdarwin -Tx -Rx is Apple Mach-O + * -Hlinux -Tx -Rx is Linux ELF32 + * -Hfreebsd -Tx -Rx is FreeBSD ELF32 + * -Hopenbsd -Tx -Rx is OpenBSD ELF32 + * -Hwindows -Tx -Rx is MS Windows PE32 */ -static int -isobjfile(char *f) +void +usage(void) { - 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; + fprint(2, "usage: 8l [-options] [-E entry] [-H head] [-I interpreter] [-L dir] [-T text] [-R rnd] [-r path] [-o out] main.8\n"); + exits("usage"); } void main(int argc, char *argv[]) { - int i, c; - char *a; + int c; Binit(&bso, 1, OWRITE); - cout = -1; listinit(); memset(debug, 0, sizeof(debug)); nerrors = 0; - outfile = "8.out"; + outfile = nil; HEADTYPE = -1; INITTEXT = -1; INITDAT = -1; INITRND = -1; INITENTRY = 0; + ARGBEGIN { default: c = ARGC(); - if(c >= 0 && c < sizeof(debug)) + if(c == 'l') + usage(); + if(c >= 0 && c < sizeof(debug)) debug[c]++; break; case 'o': /* output to (next arg) */ - outfile = ARGF(); + outfile = EARGF(usage()); break; case 'E': - a = ARGF(); - if(a) - INITENTRY = a; + INITENTRY = EARGF(usage()); break; case 'H': - a = ARGF(); - if(a) - HEADTYPE = atolwhex(a); + HEADTYPE = headtype(EARGF(usage())); + break; + case 'I': + interpreter = EARGF(usage()); + break; + case 'L': + Lflag(EARGF(usage())); break; case 'T': - a = ARGF(); - if(a) - INITTEXT = atolwhex(a); + INITTEXT = atolwhex(EARGF(usage())); break; case 'D': - a = ARGF(); - if(a) - INITDAT = atolwhex(a); + INITDAT = atolwhex(EARGF(usage())); break; case 'R': - a = ARGF(); - if(a) - INITRND = atolwhex(a); + INITRND = atolwhex(EARGF(usage())); break; - case 'x': /* produce export table */ - doexp = 1; - if(argv[1] != nil && argv[1][0] != '-' && !isobjfile(argv[1])) - readundefs(ARGF(), SEXPORT); + case 'r': + rpath = EARGF(usage()); break; - case 'u': /* produce dynamically loadable module */ - dlm = 1; - debug['l']++; - if(argv[1] != nil && argv[1][0] != '-' && !isobjfile(argv[1])) - readundefs(ARGF(), SIMPORT); - break; + case 'V': + print("%cl version %s\n", thechar, getgoversion()); + errorexit(); } ARGEND - USED(argc); - if(*argv == 0) { - diag("usage: 8l [-options] objects"); - errorexit(); + + if(argc != 1) + usage(); + + mywhatsys(); // get goos + + if(HEADTYPE == -1) + HEADTYPE = headtype(goos); + + if(outfile == nil) { + if(HEADTYPE == Hwindows) + outfile = "8.out.exe"; + else + outfile = "8.out"; } - if(!debug['9'] && !debug['U'] && !debug['B']) - debug[DEFAULT] = 1; - if(HEADTYPE == -1) { - if(debug['U']) - HEADTYPE = 1; - if(debug['B']) - HEADTYPE = 2; - if(debug['9']) - HEADTYPE = 2; - } + + libinit(); + switch(HEADTYPE) { default: diag("unknown -H option"); errorexit(); - case 0: /* this is garbage */ + case Hgarbunix: /* this is garbage */ HEADR = 20L+56L; if(INITTEXT == -1) INITTEXT = 0x40004CL; @@ -134,7 +168,7 @@ if(INITRND == -1) INITRND = 0; break; - case 1: /* is unix coff */ + case Hunixcoff: /* is unix coff */ HEADR = 0xd0L; if(INITTEXT == -1) INITTEXT = 0xd0; @@ -143,7 +177,8 @@ if(INITRND == -1) INITRND = 0; break; - case 2: /* plan 9 */ + case Hplan9x32: /* plan 9 */ + tlsoffset = -8; HEADR = 32L; if(INITTEXT == -1) INITTEXT = 4096+32; @@ -152,7 +187,7 @@ if(INITRND == -1) INITRND = 4096; break; - case 3: /* MS-DOS .COM */ + case Hmsdoscom: /* MS-DOS .COM */ HEADR = 0; if(INITTEXT == -1) INITTEXT = 0x0100; @@ -161,7 +196,7 @@ if(INITRND == -1) INITRND = 4; break; - case 4: /* fake MS-DOS .EXE */ + case Hmsdosexe: /* fake MS-DOS .EXE */ HEADR = 0x200; if(INITTEXT == -1) INITTEXT = 0x0100; @@ -171,80 +206,62 @@ INITRND = 4; HEADR += (INITTEXT & 0xFFFF); if(debug['v']) - Bprint(&bso, "HEADR = 0x%ld\n", HEADR); + Bprint(&bso, "HEADR = 0x%d\n", HEADR); break; - case 5: /* elf executable */ - HEADR = rnd(52L+3*32L, 16); + case Hdarwin: /* apple MACH */ + /* + * OS X system constant - offset from %gs to our TLS. + * Explained in ../../libcgo/darwin_386.c. + */ + tlsoffset = 0x468; + machoinit(); + HEADR = INITIAL_MACHO_HEADR; if(INITTEXT == -1) - INITTEXT = 0x80100020L; + INITTEXT = 4096+HEADR; if(INITDAT == -1) INITDAT = 0; if(INITRND == -1) INITRND = 4096; break; + case Hlinux: /* elf32 executable */ + case Hfreebsd: + case Hopenbsd: + /* + * ELF uses TLS offsets negative from %gs. + * Translate 0(GS) and 4(GS) into -8(GS) and -4(GS). + * Also known to ../../pkg/runtime/linux/386/sys.s + * and ../../libcgo/linux_386.c. + */ + tlsoffset = -8; + elfinit(); + HEADR = ELFRESERVE; + if(INITTEXT == -1) + INITTEXT = 0x08048000+HEADR; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4096; + break; + case Hwindows: /* PE executable */ + peinit(); + HEADR = PEFILEHEADR; + if(INITTEXT == -1) + INITTEXT = PEBASE+PESECTHEADR; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = PESECTALIGN; + break; } if(INITDAT != 0 && INITRND != 0) - print("warning: -D0x%lux is ignored because of -R0x%lux\n", + print("warning: -D0x%ux is ignored because of -R0x%ux\n", INITDAT, INITRND); if(debug['v']) - Bprint(&bso, "HEADER = -H0x%ld -T0x%lux -D0x%lux -R0x%lux\n", + Bprint(&bso, "HEADER = -H0x%d -T0x%ux -D0x%ux -R0x%ux\n", HEADTYPE, INITTEXT, INITDAT, INITRND); Bflush(&bso); - for(i=1; optab[i].as; i++) - if(i != optab[i].as) { - diag("phase error in optab: %d", i); - errorexit(); - } - for(i=0; i= D_AL && i <= D_BH) - reg[i] = (i-D_AL) & 7; - if(i >= D_AX && i <= D_DI) - reg[i] = (i-D_AX) & 7; - if(i >= D_F0 && i <= D_F0+7) - reg[i] = (i-D_F0) & 7; - } - + instinit(); zprg.link = P; zprg.pcond = P; zprg.back = 2; @@ -254,59 +271,25 @@ zprg.from.scale = 1; zprg.to = zprg.from; - pcstr = "%.6lux "; + pcstr = "%.6ux "; nuxiinit(); histgen = 0; - textp = P; - datap = P; - edatap = P; pc = 0; dtype = 4; - cout = create(outfile, 1, 0775); - if(cout < 0) { - diag("cannot create %s", outfile); - errorexit(); - } version = 0; cbp = buf.cbuf; cbc = sizeof(buf.cbuf); - firstp = prg(); - lastp = firstp; - if(INITENTRY == 0) { - INITENTRY = "_main"; - if(debug['p']) - INITENTRY = "_mainp"; - if(!debug['l']) - lookup(INITENTRY, 0)->type = SXREF; - } else - lookup(INITENTRY, 0)->type = SXREF; - - while(*argv) - objfile(*argv++); - if(!debug['l']) - loadlib(); - firstp = firstp->link; - if(firstp == P) - errorexit(); - if(doexp || dlm){ - EXPTAB = "_exporttab"; - zerosig(EXPTAB); - zerosig("etext"); - zerosig("edata"); - zerosig("end"); - if(dlm){ - import(); - HEADTYPE = 2; - INITTEXT = INITDAT = 0; - INITRND = 8; - INITENTRY = EXPTAB; - } - export(); - } + addlibpath("command line", "command line", argv[0], "main"); + loadlib(); + deadcode(); patch(); follow(); - dodata(); + doelf(); + if(HEADTYPE == Hdarwin) + domacho(); + if(HEADTYPE == Hwindows) + dope(); dostkoff(); if(debug['p']) if(debug['1']) @@ -314,13 +297,19 @@ else doprof2(); span(); - doinit(); + addexport(); + textaddress(); + pclntab(); + symtab(); + dodata(); + address(); + doweak(); + reloc(); asmb(); undef(); if(debug['v']) { Bprint(&bso, "%5.2f cpu time\n", cputime()); - Bprint(&bso, "%ld symbols\n", nsymbol); - Bprint(&bso, "%ld memory used\n", thunk); + Bprint(&bso, "%d symbols\n", nsymbol); Bprint(&bso, "%d sizeof adr\n", sizeof(Adr)); Bprint(&bso, "%d sizeof prog\n", sizeof(Prog)); } @@ -329,365 +318,90 @@ errorexit(); } -void -loadlib(void) -{ - int i; - long h; - Sym *s; - -loop: - xrefresolv = 0; - for(i=0; ilink) - if(s->type == SXREF) - goto loop; +static Sym* +zsym(char *pn, Biobuf *f, Sym *h[]) +{ + int o; + + o = Bgetc(f); + if(o < 0 || o >= NSYM || h[o] == nil) + mangle(pn); + return h[o]; } -void -errorexit(void) +static void +zaddr(char *pn, Biobuf *f, Adr *a, Sym *h[]) { - - if(nerrors) { - if(cout >= 0) - remove(outfile); - exits("error"); - } - exits(0); -} - -void -objfile(char *file) -{ - long off, esym, cnt, l; - int f, work; - Sym *s; - char magbuf[SARMAG]; - char name[100], pname[150]; - struct ar_hdr arhdr; - char *e, *start, *stop; - - if(file[0] == '-' && file[1] == 'l') { - if(debug['9']) - sprint(name, "/%s/lib/lib", thestring); - else - sprint(name, "/usr/%clib/lib", thechar); - strcat(name, file+2); - strcat(name, ".a"); - file = name; - } - if(debug['v']) - Bprint(&bso, "%5.2f ldobj: %s\n", cputime(), file); - Bflush(&bso); - f = open(file, 0); - if(f < 0) { - diag("cannot open file: %s", 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; - } - - 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); -} - -int -zaddr(uchar *p, Adr *a, Sym *h[]) -{ - int c, t, i; - long l; + int t; + int32 l; Sym *s; Auto *u; - t = p[0]; - - c = 1; + t = Bgetc(f); + a->index = D_NONE; + a->scale = 0; if(t & T_INDEX) { - a->index = p[c]; - a->scale = p[c+1]; - c += 2; - } else { - a->index = D_NONE; - a->scale = 0; + a->index = Bgetc(f); + a->scale = Bgetc(f); } + a->type = D_NONE; a->offset = 0; - if(t & T_OFFSET) { - a->offset = p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24); - c += 4; + if(t & T_OFFSET) + a->offset = Bget4(f); + a->offset2 = 0; + if(t & T_OFFSET2) { + a->offset2 = Bget4(f); + a->type = D_CONST2; } a->sym = S; - if(t & T_SYM) { - a->sym = h[p[c]]; - c++; - } - a->type = D_NONE; + if(t & T_SYM) + a->sym = zsym(pn, f, h); if(t & T_FCONST) { - a->ieee.l = p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24); - a->ieee.h = p[c+4] | (p[c+5]<<8) | (p[c+6]<<16) | (p[c+7]<<24); - c += 8; + a->ieee.l = Bget4(f); + a->ieee.h = Bget4(f); a->type = D_FCONST; } else if(t & T_SCONST) { - for(i=0; iscon[i] = p[c+i]; - c += NSNAME; + Bread(f, a->scon, NSNAME); a->type = D_SCONST; } - if(t & T_TYPE) { - a->type = p[c]; - c++; - } + if(t & T_TYPE) + a->type = Bgetc(f); + adrgotype = S; + if(t & T_GOTYPE) + adrgotype = zsym(pn, f, h); + + t = a->type; + if(t == D_INDIR+D_GS) + a->offset += tlsoffset; + s = a->sym; if(s == S) - return c; - - t = a->type; - if(t != D_AUTO && t != D_PARAM) - return c; + return; + if(t != D_AUTO && t != D_PARAM) { + if(adrgotype) + s->gotype = adrgotype; + return; + } l = a->offset; for(u=curauto; u; u=u->link) { if(u->asym == s) if(u->type == t) { if(u->aoffset > l) u->aoffset = l; - return c; + if(adrgotype) + u->gotype = adrgotype; + return; } } - while(nhunk < sizeof(Auto)) - gethunk(); - u = (Auto*)hunk; - nhunk -= sizeof(Auto); - hunk += sizeof(Auto); - + u = mal(sizeof(*u)); u->link = curauto; curauto = u; u->asym = s; u->aoffset = l; u->type = t; - return c; -} - -void -addlib(char *obj) -{ - char name[1024], comp[256], *p; - int i; - - if(histfrogp <= 0) - return; - - if(histfrog[0]->name[1] == '/') { - sprint(name, ""); - i = 1; - } else - if(histfrog[0]->name[1] == '.') { - sprint(name, "."); - i = 0; - } else { - if(debug['9']) - sprint(name, "/%s/lib", thestring); - else - sprint(name, "/usr/%clib", thechar); - i = 0; - } - - 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(name) + strlen(comp) + 3 >= sizeof(name)) { - diag("library component too long"); - return; - } - strcat(name, "/"); - strcat(name, comp); - } - 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) { - 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; + u->gotype = adrgotype; } void @@ -698,47 +412,25 @@ p->to.type = D_NONE; } -uchar* -readsome(int f, uchar *buf, uchar *good, uchar *stop, int max) +void +ldobj1(Biobuf *f, char *pkg, int64 len, char *pn) { - int n; + int32 ipc; + Prog *p; + int v, o, r, skip; + Sym *h[NSYM], *s; + uint32 sig; + int ntext; + int32 eof; + char *name, *x; + char src[1024]; + Prog *lastp; - 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; -} + lastp = nil; + ntext = 0; + eof = Boffset(f) + len; + src[0] = 0; -void -ldobj(int f, long c, char *pn) -{ - long ipc; - Prog *p, *t; - uchar *bloc, *bsize, *stop; - int v, o, r, skip; - Sym *h[NSYM], *s, *di; - ulong sig; - static int files; - static char **filen; - char **nfilen; - - if((files&15) == 0){ - nfilen = malloc((files+16)*sizeof(char*)); - memmove(nfilen, filen, files*sizeof(char*)); - free(filen); - filen = nfilen; - } - filen[files++] = strdup(pn); - - bsize = buf.xbuf; - bloc = buf.xbuf; - di = S; newloop: memset(h, 0, sizeof(h)); @@ -748,67 +440,57 @@ skip = 0; loop: - if(c <= 0) + if(f->state == Bracteof || Boffset(f) >= eof) goto eof; - r = bsize - bloc; - if(r < 100 && r < c) { /* enough for largest prog */ - bsize = readsome(f, buf.xbuf, bloc, bsize, c); - if(bsize == 0) - goto eof; - bloc = buf.xbuf; - goto loop; - } - o = bloc[0] | (bloc[1] << 8); + o = Bgetc(f); + if(o == Beof) + goto eof; + o |= Bgetc(f) << 8; if(o <= AXXX || o >= ALAST) { if(o < 0) goto eof; - diag("%s: opcode out of range %d", pn, o); - print(" probably not a .8 file\n"); + diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o); + print(" probably not a .%c file\n", thechar); errorexit(); } if(o == ANAME || o == ASIGNAME) { sig = 0; - if(o == ASIGNAME) { - sig = bloc[2] | (bloc[3]<<8) | (bloc[4]<<16) | (bloc[5]<<24); - bloc += 4; - c -= 4; - } - stop = memchr(&bloc[4], 0, bsize-&bloc[4]); - if(stop == 0){ - bsize = readsome(f, buf.xbuf, bloc, bsize, c); - if(bsize == 0) - goto eof; - bloc = buf.xbuf; - stop = memchr(&bloc[4], 0, bsize-&bloc[4]); - if(stop == 0){ + if(o == ASIGNAME) + sig = Bget4(f); + v = Bgetc(f); /* type */ + o = Bgetc(f); /* sym */ + r = 0; + if(v == D_STATIC) + r = version; + name = Brdline(f, '\0'); + if(name == nil) { + if(Blinelen(f) > 0) { fprint(2, "%s: name too long\n", pn); errorexit(); } + goto eof; } - v = bloc[2]; /* type */ - o = bloc[3]; /* sym */ - bloc += 4; - c -= 4; - - r = 0; - if(v == D_STATIC) - r = version; - s = lookup((char*)bloc, r); - c -= &stop[1] - bloc; - bloc = stop + 1; + x = expandpkg(name, pkg); + s = lookup(x, r); + if(x != name) + free(x); if(debug['S'] && r == 0) sig = 1729; if(sig != 0){ if(s->sig != 0 && s->sig != sig) - diag("incompatible type signatures %lux(%s) and %lux(%s) for %s", s->sig, filen[s->file], sig, pn, s->name); + diag("incompatible type signatures" + "%ux(%s) and %ux(%s) for %s", + s->sig, s->file, sig, pn, s->name); s->sig = sig; - s->file = files-1; + s->file = pn; } if(debug['W']) print(" ANAME %s\n", s->name); + if(o < 0 || o >= nelem(h)) + mangle(pn); h[o] = s; if((v == D_EXTERN || v == D_STATIC) && s->type == 0) s->type = SXREF; @@ -823,23 +505,20 @@ histfrogp++; } else collapsefrog(s); + dwarfaddfrag(s->value, s->name); } goto loop; } - while(nhunk < sizeof(Prog)) - gethunk(); - p = (Prog*)hunk; - nhunk -= sizeof(Prog); - hunk += sizeof(Prog); - + p = mal(sizeof(*p)); p->as = o; - p->line = bloc[2] | (bloc[3] << 8) | (bloc[4] << 16) | (bloc[5] << 24); + p->line = Bget4(f); p->back = 2; - r = zaddr(bloc+6, &p->from, h) + 6; - r += zaddr(bloc+r, &p->to, h); - bloc += r; - c -= r; + p->ft = 0; + p->tt = 0; + zaddr(pn, f, &p->from, h); + fromgotype = adrgotype; + zaddr(pn, f, &p->to, h); if(debug['W']) print("%P\n", p); @@ -847,10 +526,12 @@ switch(p->as) { case AHISTORY: if(p->to.offset == -1) { - addlib(pn); + addlib(src, pn); histfrogp = 0; goto loop; } + if(src[0] == '\0') + copyhistfrog(src, sizeof src); addhist(p->line, D_FILE); /* 'z' */ if(p->to.offset) addhist(p->to.offset, D_FILE1); /* 'Z' */ @@ -859,79 +540,53 @@ case AEND: histtoauto(); - if(curtext != P) - curtext->to.autom = curauto; + if(cursym != nil && cursym->text) + cursym->autom = curauto; curauto = 0; - curtext = P; - if(c) - goto newloop; - return; + cursym = nil; + if(Boffset(f) == eof) + return; + goto newloop; case AGLOBL: s = p->from.sym; if(s->type == 0 || s->type == SXREF) { s->type = SBSS; - s->value = 0; + s->size = 0; } - if(s->type != SBSS) { + if(s->type != SBSS && !s->dupok) { diag("%s: redefinition: %s in %s", pn, s->name, TNAME); s->type = SBSS; - s->value = 0; + s->size = 0; } - if(p->to.offset > s->value) - s->value = p->to.offset; + if(p->to.offset > s->size) + s->size = p->to.offset; + if(p->from.scale & DUPOK) + s->dupok = 1; + if(p->from.scale & RODATA) + s->type = SRODATA; goto loop; - case ADYNT: - if(p->to.sym == S) { - diag("DYNT without a sym\n%P", p); - break; + case ADATA: + // Assume that AGLOBL comes after ADATA. + // If we've seen an AGLOBL that said this sym was DUPOK, + // ignore any more ADATA we see, which must be + // redefinitions. + s = p->from.sym; + if(s->dupok) { +// if(debug['v']) +// Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn); + goto loop; } - di = p->to.sym; - p->from.scale = 4; - if(di->type == SXREF) { - if(debug['z']) - Bprint(&bso, "%P set to %d\n", p, dtype); - di->type = SCONST; - di->value = dtype; - dtype += 4; + if(s->file == nil) + s->file = pn; + else if(s->file != pn) { + diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn); + errorexit(); } - if(p->from.sym == S) - break; - - p->from.offset = di->value; - p->from.sym->type = SDATA; - if(curtext == P) { - diag("DYNT not in text: %P", p); - break; - } - p->to.sym = curtext->from.sym; - p->to.type = D_ADDR; - p->to.index = D_EXTERN; - goto data; - - case AINIT: - if(p->from.sym == S) { - diag("INIT without a sym\n%P", p); - break; - } - if(di == S) { - diag("INIT without previous DYNT\n%P", p); - break; - } - p->from.offset = di->value; - p->from.sym->type = SDATA; - goto data; - - case ADATA: - data: - if(edatap == P) - datap = p; - else - edatap->link = p; - edatap = p; - p->link = P; + savedata(s, p, pn); + unmal(p, sizeof *p); goto loop; case AGOK: @@ -940,18 +595,30 @@ goto loop; case ATEXT: - if(curtext != P) { + s = p->from.sym; + if(s->text != nil) { + diag("%s: %s: redefinition", pn, s->name); + return; + } + if(ntext++ == 0 && s->type != 0 && s->type != SXREF) { + /* redefinition, so file has probably been seen before */ + if(debug['v']) + diag("skipping: %s: redefinition: %s", pn, s->name); + return; + } + if(cursym != nil && cursym->text) { histtoauto(); - curtext->to.autom = curauto; + cursym->autom = curauto; curauto = 0; } skip = 0; - curtext = p; - s = p->from.sym; - if(s == S) { - diag("%s: no TEXT symbol: %P", pn, p); - errorexit(); - } + if(etextp) + etextp->next = s; + else + textp = s; + etextp = s; + s->text = p; + cursym = s; if(s->type != 0 && s->type != SXREF) { if(p->from.scale & DUPOK) { skip = 1; @@ -961,17 +628,8 @@ } s->type = STEXT; s->value = pc; - lastp->link = p; lastp = p; - p->pc = pc; - pc++; - if(textp == P) { - textp = p; - etextp = p; - goto loop; - } - etextp->pcond = p; - etextp = p; + p->pc = pc++; goto loop; case AFMOVF: @@ -987,24 +645,12 @@ goto casdef; if(p->from.type == D_FCONST) { /* size sb 9 max */ - sprint(literal, "$%lux", ieeedtof(&p->from.ieee)); + sprint(literal, "$%ux", ieeedtof(&p->from.ieee)); s = lookup(literal, 0); if(s->type == 0) { - s->type = SBSS; - s->value = 4; - t = prg(); - t->as = ADATA; - t->line = p->line; - t->from.type = D_EXTERN; - t->from.sym = s; - t->from.scale = 4; - t->to = p->from; - if(edatap == P) - datap = t; - else - edatap->link = t; - edatap = t; - t->link = P; + s->type = SDATA; + adduint32(s, ieeedtof(&p->from.ieee)); + s->reachable = 0; } p->from.type = D_EXTERN; p->from.sym = s; @@ -1025,25 +671,14 @@ goto casdef; if(p->from.type == D_FCONST) { /* size sb 18 max */ - sprint(literal, "$%lux.%lux", + sprint(literal, "$%ux.%ux", p->from.ieee.l, p->from.ieee.h); s = lookup(literal, 0); if(s->type == 0) { - s->type = SBSS; - s->value = 8; - t = prg(); - t->as = ADATA; - t->line = p->line; - t->from.type = D_EXTERN; - t->from.sym = s; - t->from.scale = 8; - t->to = p->from; - if(edatap == P) - datap = t; - else - edatap->link = t; - edatap = t; - t->link = P; + s->type = SDATA; + adduint32(s, p->from.ieee.l); + adduint32(s, p->from.ieee.h); + s->reachable = 0; } p->from.type = D_EXTERN; p->from.sym = s; @@ -1055,71 +690,31 @@ default: if(skip) nopout(p); + p->pc = pc; + pc++; if(p->to.type == D_BRANCH) p->to.offset += ipc; + if(lastp == nil) { + if(p->as != ANOP) + diag("unexpected instruction: %P", p); + goto loop; + } lastp->link = p; lastp = p; - p->pc = pc; - pc++; goto loop; } - goto loop; eof: diag("truncated object file: %s", pn); } -Sym* -lookup(char *symb, int v) -{ - Sym *s; - char *p; - long h; - int l, c; - - 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; - - while(nhunk < sizeof(Sym)) - gethunk(); - s = (Sym*)hunk; - nhunk -= sizeof(Sym); - hunk += 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; - nsymbol++; - return s; -} - Prog* prg(void) { Prog *p; - while(nhunk < sizeof(Prog)) - gethunk(); - p = (Prog*)hunk; - nhunk -= sizeof(Prog); - hunk += sizeof(Prog); - + p = mal(sizeof(Prog)); *p = zprg; return p; } @@ -1145,389 +740,3 @@ p->line = q->line; return p; } - -void -gethunk(void) -{ - char *h; - long nh; - - nh = NHUNK; - if(thunk >= 5L*NHUNK) { - nh = 5L*NHUNK; - if(thunk >= 25L*NHUNK) - nh = 25L*NHUNK; - } - h = mysbrk(nh); - if(h == (char*)-1) { - diag("out of memory"); - errorexit(); - } - hunk = h; - nhunk = nh; - thunk += nh; -} - -void -doprof1(void) -{ - Sym *s; - long n; - Prog *p, *q; - - if(debug['v']) - Bprint(&bso, "%5.2f profile 1\n", cputime()); - Bflush(&bso); - s = lookup("__mcount", 0); - n = 1; - for(p = firstp->link; p != P; p = p->link) { - if(p->as == ATEXT) { - q = prg(); - q->line = p->line; - q->link = datap; - datap = q; - q->as = ADATA; - q->from.type = D_EXTERN; - q->from.offset = n*4; - q->from.sym = s; - q->from.scale = 4; - q->to = p->from; - q->to.type = D_CONST; - - q = prg(); - q->line = p->line; - q->pc = p->pc; - q->link = p->link; - p->link = q; - p = q; - p->as = AADDL; - p->from.type = D_CONST; - p->from.offset = 1; - p->to.type = D_EXTERN; - p->to.sym = s; - p->to.offset = n*4 + 4; - - n += 2; - continue; - } - } - q = prg(); - q->line = 0; - q->link = datap; - datap = q; - - q->as = ADATA; - q->from.type = D_EXTERN; - q->from.sym = s; - q->from.scale = 4; - q->to.type = D_CONST; - q->to.offset = n; - - s->type = SBSS; - s->value = n*4; -} - -void -doprof2(void) -{ - Sym *s2, *s4; - Prog *p, *q, *q2, *ps2, *ps4; - - if(debug['v']) - Bprint(&bso, "%5.2f profile 2\n", cputime()); - Bflush(&bso); - - if(debug['e']){ - s2 = lookup("_tracein", 0); - s4 = lookup("_traceout", 0); - }else{ - s2 = lookup("_profin", 0); - s4 = lookup("_profout", 0); - } - if(s2->type != STEXT || s4->type != STEXT) { - if(debug['e']) - diag("_tracein/_traceout not defined %d %d", s2->type, s4->type); - else - diag("_profin/_profout not defined"); - return; - } - - ps2 = P; - ps4 = P; - for(p = firstp; p != P; p = p->link) { - if(p->as == ATEXT) { - if(p->from.sym == s2) { - p->from.scale = 1; - ps2 = p; - } - if(p->from.sym == s4) { - p->from.scale = 1; - ps4 = p; - } - } - } - for(p = firstp; p != P; p = p->link) { - if(p->as == ATEXT) { - curtext = p; - - if(p->from.scale & NOPROF) { /* dont profile */ - for(;;) { - q = p->link; - if(q == P) - break; - if(q->as == ATEXT) - break; - p = q; - } - continue; - } - - /* - * JMPL profin - */ - q = prg(); - q->line = p->line; - q->pc = p->pc; - q->link = p->link; - if(debug['e']){ /* embedded tracing */ - q2 = prg(); - p->link = q2; - q2->link = q; - - q2->line = p->line; - q2->pc = p->pc; - - q2->as = AJMP; - q2->to.type = D_BRANCH; - q2->to.sym = p->to.sym; - q2->pcond = q->link; - }else - p->link = q; - p = q; - p->as = ACALL; - p->to.type = D_BRANCH; - p->pcond = ps2; - p->to.sym = s2; - - continue; - } - if(p->as == ARET) { - /* - * RET (default) - */ - if(debug['e']){ /* embedded tracing */ - q = prg(); - q->line = p->line; - q->pc = p->pc; - q->link = p->link; - p->link = q; - p = q; - } - /* - * RET - */ - q = prg(); - q->as = ARET; - q->from = p->from; - q->to = p->to; - q->link = p->link; - p->link = q; - - /* - * JAL profout - */ - p->as = ACALL; - p->from = zprg.from; - p->to = zprg.to; - p->to.type = D_BRANCH; - p->pcond = ps4; - p->to.sym = s4; - - p = q; - - continue; - } - } -} - -void -nuxiinit(void) -{ - int i, c; - - for(i=0; i<4; i++) { - c = find1(0x04030201L, i+1); - if(i < 2) - inuxi2[i] = c; - if(i < 1) - inuxi1[i] = c; - inuxi4[i] = c; - fnuxi4[i] = c; - fnuxi8[i] = c; - fnuxi8[i+4] = c+4; - } - if(debug['v']) { - Bprint(&bso, "inuxi = "); - for(i=0; i<1; i++) - Bprint(&bso, "%d", inuxi1[i]); - Bprint(&bso, " "); - for(i=0; i<2; i++) - Bprint(&bso, "%d", inuxi2[i]); - Bprint(&bso, " "); - for(i=0; i<4; i++) - Bprint(&bso, "%d", inuxi4[i]); - Bprint(&bso, "\nfnuxi = "); - for(i=0; i<4; i++) - Bprint(&bso, "%d", fnuxi4[i]); - Bprint(&bso, " "); - for(i=0; i<8; i++) - Bprint(&bso, "%d", fnuxi8[i]); - Bprint(&bso, "\n"); - } - Bflush(&bso); -} - -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; -} - -int -find2(long l, int c) -{ - short *p; - int i; - - p = (short*)&l; - for(i=0; i<4; i+=2) { - if(((*p >> 8) & 0xff) == c) - return i; - if((*p++ & 0xff) == c) - return i+1; - } - return 0; -} - -long -ieeedtof(Ieee *e) -{ - int exp; - long v; - - if(e->h == 0) - return 0; - exp = (e->h>>20) & ((1L<<11)-1L); - exp -= (1L<<10) - 2L; - v = (e->h & 0xfffffL) << 3; - v |= (e->l >> 29) & 0x7L; - if((e->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 |= e->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); -} - -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 -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); -} diff -r d8d00747375b sys/src/cmd/8l/optab.c --- a/sys/src/cmd/8l/optab.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/8l/optab.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,3 +1,33 @@ +// Inferno utils/8l/optab.c +// http://code.google.com/p/inferno-os/source/browse/utils/8l/optab.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" uchar ynone[] = @@ -143,6 +173,11 @@ Yml, Yrl, Zm_r, 1, 0 }; +uchar yrb_mb[] = +{ + Yrb, Ymb, Zr_m, 1, + 0 +}; uchar yrl_ml[] = { Yrl, Yml, Zr_m, 1, @@ -225,13 +260,16 @@ uchar ycall[] = { Ynone, Yml, Zo_m, 2, - Ynone, Ybr, Zcall, 1, + Ynone, Ycol, Zcallind, 2, + Ynone, Ybr, Zcall, 0, + Ynone, Yi32, Zcallcon, 1, 0 }; uchar yjmp[] = { Ynone, Yml, Zo_m, 2, - Ynone, Ybr, Zjmp, 1, + Ynone, Ybr, Zjmp, 0, + Ynone, Yi32, Zjmpcon, 1, 0 }; @@ -265,6 +303,11 @@ Yf0, Ym, Zo_m, 2, 0 }; +uchar yfcmv[] = +{ + Yrf, Yf0, Zm_o, 2, + 0 +}; uchar yfadd[] = { Ym, Yf0, Zm_o, 2, @@ -341,7 +384,7 @@ { ABTSL, yml_rl, Pm, 0xab }, { ABTSW, yml_rl, Pq, 0xab }, { ABYTE, ybyte, Px, 1 }, - { ACALL, ycall, Px, 0xff,(02),0xe8 }, + { ACALL, ycall, Px, 0xff,(02),0xff,(0x15),0xe8 }, { ACLC, ynone, Px, 0xf8 }, { ACLD, ynone, Px, 0xfc }, { ACLI, ynone, Px, 0xfa }, @@ -388,7 +431,8 @@ { AIRETW, ynone, Pe, 0xcf }, { AJCC, yjcond, Px, 0x73,0x83,(00) }, { AJCS, yjcond, Px, 0x72,0x82 }, - { AJCXZ, yloop, Px, 0xe3 }, + { AJCXZL, yloop, Px, 0xe3 }, + { AJCXZW, yloop, Px, 0xe3 }, { AJEQ, yjcond, Px, 0x74,0x84 }, { AJGE, yjcond, Px, 0x7d,0x8d }, { AJGT, yjcond, Px, 0x7f,0x8f }, @@ -453,6 +497,7 @@ { AOUTSB, ynone, Pb, 0x6e }, { AOUTSL, ynone, Px, 0x6f }, { AOUTSW, ynone, Pe, 0x6f }, + { APAUSE, ynone, Px, 0xf3,0x90 }, { APOPAL, ynone, Px, 0x61 }, { APOPAW, ynone, Pe, 0x61 }, { APOPFL, ynone, Px, 0x9d }, @@ -565,13 +610,17 @@ { AFCOMDPP, ycompp, Px, 0xde,(03) }, { AFCOMF, yfmvx, Px, 0xd8,(02) }, { AFCOMFP, yfmvx, Px, 0xd8,(03) }, + { AFCOMI, yfmvx, Px, 0xdb,(06) }, + { AFCOMIP, yfmvx, Px, 0xdf,(06) }, { AFCOML, yfmvx, Px, 0xda,(02) }, { AFCOMLP, yfmvx, Px, 0xda,(03) }, { AFCOMW, yfmvx, Px, 0xde,(02) }, { AFCOMWP, yfmvx, Px, 0xde,(03) }, { AFUCOM, ycompp, Px, 0xdd,(04) }, - { AFUCOMP, ycompp, Px, 0xdd,(05) }, + { AFUCOMI, ycompp, Px, 0xdb,(05) }, + { AFUCOMIP, ycompp, Px, 0xdf,(05) }, + { AFUCOMP, ycompp, Px, 0xdd,(05) }, { AFUCOMPP, ycompp, Px, 0xda,(13) }, { AFADDDP, yfaddp, Px, 0xde,(00) }, @@ -650,5 +699,59 @@ { AFYL2X, ynone, Px, 0xd9, 0xf1 }, { AFYL2XP1, ynone, Px, 0xd9, 0xf9 }, { AEND }, + { ADYNT_ }, + { AINIT_ }, + { ASIGNAME }, + { ACMPXCHGB, yrb_mb, Pm, 0xb0 }, + { ACMPXCHGL, yrl_ml, Pm, 0xb1 }, + { ACMPXCHGW, yrl_ml, Pm, 0xb1 }, + { ACMPXCHG8B, yscond, Pm, 0xc7,(01) }, + + { AXADDB, yrb_mb, Pb, 0x0f,0xc0 }, + { AXADDL, yrl_ml, Pm, 0xc1 }, + { AXADDW, yrl_ml, Pe, 0x0f,0xc1 }, + + { ACMOVLCC, yml_rl, Pm, 0x43 }, + { ACMOVLCS, yml_rl, Pm, 0x42 }, + { ACMOVLEQ, yml_rl, Pm, 0x44 }, + { ACMOVLGE, yml_rl, Pm, 0x4d }, + { ACMOVLGT, yml_rl, Pm, 0x4f }, + { ACMOVLHI, yml_rl, Pm, 0x47 }, + { ACMOVLLE, yml_rl, Pm, 0x4e }, + { ACMOVLLS, yml_rl, Pm, 0x46 }, + { ACMOVLLT, yml_rl, Pm, 0x4c }, + { ACMOVLMI, yml_rl, Pm, 0x48 }, + { ACMOVLNE, yml_rl, Pm, 0x45 }, + { ACMOVLOC, yml_rl, Pm, 0x41 }, + { ACMOVLOS, yml_rl, Pm, 0x40 }, + { ACMOVLPC, yml_rl, Pm, 0x4b }, + { ACMOVLPL, yml_rl, Pm, 0x49 }, + { ACMOVLPS, yml_rl, Pm, 0x4a }, + { ACMOVWCC, yml_rl, Pq, 0x43 }, + { ACMOVWCS, yml_rl, Pq, 0x42 }, + { ACMOVWEQ, yml_rl, Pq, 0x44 }, + { ACMOVWGE, yml_rl, Pq, 0x4d }, + { ACMOVWGT, yml_rl, Pq, 0x4f }, + { ACMOVWHI, yml_rl, Pq, 0x47 }, + { ACMOVWLE, yml_rl, Pq, 0x4e }, + { ACMOVWLS, yml_rl, Pq, 0x46 }, + { ACMOVWLT, yml_rl, Pq, 0x4c }, + { ACMOVWMI, yml_rl, Pq, 0x48 }, + { ACMOVWNE, yml_rl, Pq, 0x45 }, + { ACMOVWOC, yml_rl, Pq, 0x41 }, + { ACMOVWOS, yml_rl, Pq, 0x40 }, + { ACMOVWPC, yml_rl, Pq, 0x4b }, + { ACMOVWPL, yml_rl, Pq, 0x49 }, + { ACMOVWPS, yml_rl, Pq, 0x4a }, + + { AFCMOVCC, yfcmv, Px, 0xdb,(00) }, + { AFCMOVCS, yfcmv, Px, 0xda,(00) }, + { AFCMOVEQ, yfcmv, Px, 0xda,(01) }, + { AFCMOVHI, yfcmv, Px, 0xdb,(02) }, + { AFCMOVLS, yfcmv, Px, 0xda,(02) }, + { AFCMOVNE, yfcmv, Px, 0xdb,(01) }, + { AFCMOVNU, yfcmv, Px, 0xdb,(03) }, + { AFCMOVUN, yfcmv, Px, 0xda,(03) }, + 0 }; diff -r d8d00747375b sys/src/cmd/8l/pass.c --- a/sys/src/cmd/8l/pass.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/8l/pass.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,101 +1,40 @@ +// Inferno utils/8l/pass.c +// http://code.google.com/p/inferno-os/source/browse/utils/8l/pass.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. + +// Code and data passes. + #include "l.h" +#include "../ld/lib.h" +#include "../ld/stack.h" -void -dodata(void) -{ - int i; - Sym *s; - Prog *p; - long t, u; - - 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); - t = p->from.offset + p->width; - if(t > s->value) - diag("initialize bounds (%ld): %s\n%P", - s->value, s->name, p); - } - /* allocate small guys */ - datsize = 0; - for(i=0; ilink) { - if(s->type != SDATA) - if(s->type != SBSS) - continue; - t = s->value; - if(t == 0) { - diag("%s: no size", s->name); - t = 1; - } - t = rnd(t, 4);; - s->value = t; - if(t > MINSIZ) - continue; - s->value = datsize; - datsize += t; - s->type = SDATA1; - } - - /* allocate the rest of the data */ - for(i=0; ilink) { - if(s->type != SDATA) { - if(s->type == SDATA1) - s->type = SDATA; - continue; - } - t = s->value; - s->value = datsize; - datsize += t; - } - - if(debug['j']) { - /* - * pad data with bss that fits up to next - * 8k boundary, then push data to 8k - */ - u = rnd(datsize, 8192); - u -= datsize; - for(i=0; ilink) { - if(s->type != SBSS) - continue; - t = s->value; - if(t > u) - continue; - u -= t; - s->value = datsize; - s->type = SDATA; - datsize += t; - } - datsize += u; - } - - /* now the bss */ - bsssize = 0; - for(i=0; ilink) { - if(s->type != SBSS) - continue; - t = s->value; - s->value = bsssize + datsize; - bsssize += t; - } - xdefine("bdata", SDATA, 0L); - xdefine("edata", SBSS, datsize); - xdefine("end", SBSS, bsssize + datsize); - /* etext is defined in span.c */ -} +static void xfol(Prog*, Prog**); Prog* brchain(Prog *p) @@ -113,19 +52,53 @@ void follow(void) { + Prog *firstp, *lastp; if(debug['v']) Bprint(&bso, "%5.2f follow\n", cputime()); Bflush(&bso); - firstp = prg(); - lastp = firstp; - xfol(textp); - lastp->link = P; - firstp = firstp->link; + + for(cursym = textp; cursym != nil; cursym = cursym->next) { + firstp = prg(); + lastp = firstp; + xfol(cursym->text, &lastp); + lastp->link = nil; + cursym->text = firstp->link; + } } -void -xfol(Prog *p) +static int +nofollow(int a) +{ + switch(a) { + case AJMP: + case ARET: + case AIRETL: + case AIRETW: + return 1; + } + return 0; +} + +static int +pushpop(int a) +{ + switch(a) { + case APUSHL: + case APUSHFL: + case APUSHW: + case APUSHFW: + case APOPL: + case APOPFL: + case APOPW: + case APOPFW: + return 1; + } + return 0; +} + +static void +xfol(Prog *p, Prog **last) { Prog *q; int i; @@ -134,42 +107,31 @@ loop: if(p == P) return; - if(p->as == ATEXT) - curtext = p; if(p->as == AJMP) - if((q = p->pcond) != P) { + if((q = p->pcond) != P && q->as != ATEXT) { + /* mark instruction as done and continue layout at target of jump */ p->mark = 1; p = q; if(p->mark == 0) goto loop; } if(p->mark) { - /* copy up to 4 instructions to avoid branch */ + /* + * p goes here, but already used it elsewhere. + * copy up to 4 instructions or else branch to other copy. + */ for(i=0,q=p; i<4; i++,q=q->link) { if(q == P) break; - if(q == lastp) + if(q == *last) break; a = q->as; if(a == ANOP) { i--; continue; } - switch(a) { - case AJMP: - case ARET: - case AIRETL: - - case APUSHL: - case APUSHFL: - case APUSHW: - case APUSHFW: - case APOPL: - case APOPFL: - case APOPW: - case APOPFW: - goto brk; - } + if(nofollow(a) || pushpop(a)) + break; // NOTE(rsc): arm does goto copy if(q->pcond == P || q->pcond->mark) continue; if(a == ACALL || a == ALOOP) @@ -182,8 +144,8 @@ q = copyp(p); p = p->link; q->mark = 1; - lastp->link = q; - lastp = q; + (*last)->link = q; + *last = q; if(q->as != a || q->pcond == P || q->pcond->mark) continue; @@ -191,14 +153,13 @@ p = q->pcond; q->pcond = q->link; q->link = p; - xfol(q->link); + xfol(q->link, last); p = q->link; if(p->mark) return; goto loop; } } /* */ - brk:; q = prg(); q->as = AJMP; q->line = p->line; @@ -207,14 +168,22 @@ q->pcond = p; p = q; } + + /* emit p */ p->mark = 1; - lastp->link = p; - lastp = p; + (*last)->link = p; + *last = p; a = p->as; - if(a == AJMP || a == ARET || a == AIRETL) + + /* continue loop with what comes after p */ + if(nofollow(a)) return; - if(p->pcond != P) - if(a != ACALL) { + if(p->pcond != P && a != ACALL) { + /* + * some kind of conditional branch. + * recurse to follow one path. + * continue loop on the other. + */ q = brchain(p->link); if(q != P && q->mark) if(a != ALOOP) { @@ -222,7 +191,7 @@ p->link = p->pcond; p->pcond = q; } - xfol(p->link); + xfol(p->link, last); q = brchain(p->pcond); if(q->mark) { p->pcond = q; @@ -262,34 +231,13 @@ } void -doinit(void) -{ - Sym *s; - Prog *p; - int x; - - for(p = datap; p != P; p = p->link) { - x = p->to.type; - if(x != D_EXTERN && x != D_STATIC) - continue; - s = p->to.sym; - if(s->type == 0 || s->type == SXREF) - diag("undefined %s initializer of %s", - s->name, p->from.sym->name); - p->to.offset += s->value; - p->to.type = D_CONST; - if(s->type == SDATA || s->type == SBSS) - p->to.offset += INITDAT; - } -} - -void patch(void) { - long c; + int32 c; Prog *p, *q; Sym *s; - long vexit; + int32 vexit; + Sym *plan9_tos; if(debug['v']) Bprint(&bso, "%5.2f mkfwd\n", cputime()); @@ -300,95 +248,120 @@ Bflush(&bso); s = lookup("exit", 0); vexit = s->value; - for(p = firstp; p != P; p = p->link) { - if(p->as == ATEXT) - curtext = p; - if(p->as == ACALL || p->as == ARET) { - s = p->to.sym; - if(s) { - if(debug['c']) - Bprint(&bso, "%s calls %s\n", TNAME, s->name); - switch(s->type) { - default: - /* diag prints TNAME first */ - diag("%s is undefined", s->name); - s->type = STEXT; - s->value = vexit; - break; /* or fall through to set offset? */ - case STEXT: - p->to.offset = s->value; + + plan9_tos = S; + if(HEADTYPE == Hplan9x32) + plan9_tos = lookup("_tos", 0); + + for(cursym = textp; cursym != nil; cursym = cursym->next) { + for(p = cursym->text; p != P; p = p->link) { + if(HEADTYPE == Hwindows) { + // Convert + // op n(GS), reg + // to + // MOVL 0x2C(FS), reg + // op n(reg), reg + // The purpose of this patch is to fix some accesses + // to extern register variables (TLS) on Windows, as + // a different method is used to access them. + if(p->from.type == D_INDIR+D_GS + && p->to.type >= D_AX && p->to.type <= D_DI) { + q = appendp(p); + q->from = p->from; + q->from.type = D_INDIR + p->to.type; + q->to = p->to; + q->as = p->as; + p->as = AMOVL; + p->from.type = D_INDIR+D_FS; + p->from.offset = 0x2C; + } + } + if(HEADTYPE == Hlinux) { + // Running binaries under Xen requires using + // MOVL 0(GS), reg + // and then off(reg) instead of saying off(GS) directly + // when the offset is negative. + if(p->from.type == D_INDIR+D_GS && p->from.offset < 0 + && p->to.type >= D_AX && p->to.type <= D_DI) { + q = appendp(p); + q->from = p->from; + q->from.type = D_INDIR + p->to.type; + q->to = p->to; + q->as = p->as; + p->as = AMOVL; + p->from.type = D_INDIR+D_GS; + p->from.offset = 0; + } + } + if(HEADTYPE == Hplan9x32) { + if(p->from.type == D_INDIR+D_GS + && p->to.type >= D_AX && p->to.type <= D_DI) { + q = appendp(p); + q->from = p->from; + q->from.type = D_INDIR + p->to.type; + q->to = p->to; + q->as = p->as; + p->as = AMOVL; + p->from.type = D_EXTERN; + p->from.sym = plan9_tos; + p->from.offset = 0; + } + } + if((p->as == ACALL && p->to.type != D_BRANCH) || (p->as == AJMP && p->to.type != D_BRANCH)) { + s = p->to.sym; + if(p->to.type == D_INDIR+D_ADDR) { + /* skip check if this is an indirect call (CALL *symbol(SB)) */ + continue; + } else if(s) { + if(debug['c']) + Bprint(&bso, "%s calls %s\n", TNAME, s->name); + if((s->type&~SSUB) != STEXT) { + /* diag prints TNAME first */ + diag("undefined: %s", s->name); + s->type = STEXT; + s->value = vexit; + continue; // avoid more error messages + } + if(s->text == nil) + continue; + p->to.type = D_BRANCH; + p->to.offset = s->text->pc; + p->pcond = s->text; + continue; + } + } + if(p->to.type != D_BRANCH) + continue; + c = p->to.offset; + for(q = cursym->text; q != P;) { + if(c == q->pc) break; - case SUNDEF: - p->pcond = UP; - p->to.offset = 0; - break; - } - p->to.type = D_BRANCH; + if(q->forwd != P && c >= q->forwd->pc) + q = q->forwd; + else + q = q->link; } + if(q == P) { + diag("branch out of range in %s (%#ux)\n%P [%s]", + TNAME, c, p, p->to.sym ? p->to.sym->name : ""); + p->to.type = D_NONE; + } + p->pcond = q; } - if(p->to.type != D_BRANCH || p->pcond == UP) - continue; - c = p->to.offset; - 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 in %s\n%P", TNAME, p); - p->to.type = D_NONE; - } - p->pcond = q; } - for(p = firstp; p != P; p = p->link) { - if(p->as == ATEXT) - curtext = p; - p->mark = 0; /* initialization for follow */ - if(p->pcond != P && p->pcond != UP) { - p->pcond = brloop(p->pcond); - if(p->pcond != P) - if(p->to.type == D_BRANCH) - p->to.offset = p->pcond->pc; - } - } -} + for(cursym = textp; cursym != nil; cursym = cursym->next) { + if(cursym->text == nil || cursym->p != nil) + continue; -#define LOG 5 -void -mkfwd(void) -{ - Prog *p; - int i; - long dwn[LOG], cnt[LOG]; - 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; + for(p = cursym->text; p != P; p = p->link) { + p->mark = 0; /* initialization for follow */ + if(p->pcond != P) { + p->pcond = brloop(p->pcond); + if(p->pcond != P) + if(p->to.type == D_BRANCH) + p->to.offset = p->pcond->pc; + } } } } @@ -413,165 +386,243 @@ void dostkoff(void) { - Prog *p, *q; - long autoffset, deltasp; - int a, f, curframe, curbecome, maxbecome; + Prog *p, *q, *q1; + int32 autoffset, deltasp; + int a; + Prog *pmorestack; + Sym *symmorestack; + Sym *plan9_tos; - curframe = 0; - curbecome = 0; - maxbecome = 0; - curtext = 0; - for(p = firstp; p != P; p = p->link) { + pmorestack = P; + symmorestack = lookup("runtime.morestack", 0); - /* find out how much arg space is used in this TEXT */ - if(p->to.type == (D_INDIR+D_SP)) - if(p->to.offset > curframe) - curframe = p->to.offset; + if(symmorestack->type != STEXT) + diag("runtime.morestack not defined"); + else { + pmorestack = symmorestack->text; + symmorestack->text->from.scale |= NOSPLIT; + } + + plan9_tos = S; + if(HEADTYPE == Hplan9x32) + plan9_tos = lookup("_tos", 0); - switch(p->as) { - case ATEXT: - if(curtext && curtext->from.sym) { - curtext->from.sym->frame = curframe; - curtext->from.sym->become = curbecome; - if(curbecome > maxbecome) - maxbecome = curbecome; + for(cursym = textp; cursym != nil; cursym = cursym->next) { + if(cursym->text == nil || cursym->text->link == nil) + continue; + + p = cursym->text; + autoffset = p->to.offset; + if(autoffset < 0) + autoffset = 0; + + q = P; + if(pmorestack != P) + if(!(p->from.scale & NOSPLIT)) { + p = appendp(p); // load g into CX + switch(HEADTYPE) { + case Hwindows: + p->as = AMOVL; + p->from.type = D_INDIR+D_FS; + p->from.offset = 0x2c; + p->to.type = D_CX; + + p = appendp(p); + p->as = AMOVL; + p->from.type = D_INDIR+D_CX; + p->from.offset = 0; + p->to.type = D_CX; + break; + + case Hlinux: + p->as = AMOVL; + p->from.type = D_INDIR+D_GS; + p->from.offset = 0; + p->to.type = D_CX; + + p = appendp(p); + p->as = AMOVL; + p->from.type = D_INDIR+D_CX; + p->from.offset = tlsoffset + 0; + p->to.type = D_CX; + break; + + case Hplan9x32: + p->as = AMOVL; + p->from.type = D_EXTERN; + p->from.sym = plan9_tos; + p->to.type = D_CX; + + p = appendp(p); + p->as = AMOVL; + p->from.type = D_INDIR+D_CX; + p->from.offset = tlsoffset + 0; + p->to.type = D_CX; + break; + + default: + p->as = AMOVL; + p->from.type = D_INDIR+D_GS; + p->from.offset = tlsoffset + 0; + p->to.type = D_CX; } - curframe = 0; - curbecome = 0; - curtext = p; - break; + if(debug['K']) { + // 8l -K means check not only for stack + // overflow but stack underflow. + // On underflow, INT 3 (breakpoint). + // Underflow itself is rare but this also + // catches out-of-sync stack guard info. + p = appendp(p); + p->as = ACMPL; + p->from.type = D_INDIR+D_CX; + p->from.offset = 4; + p->to.type = D_SP; - case ARET: - /* special form of RET is BECOME */ - if(p->from.type == D_CONST) - if(p->from.offset > curbecome) - curbecome = p->from.offset; - break; + p = appendp(p); + p->as = AJCC; + p->to.type = D_BRANCH; + p->to.offset = 4; + q1 = p; + + p = appendp(p); + p->as = AINT; + p->from.type = D_CONST; + p->from.offset = 3; + + p = appendp(p); + p->as = ANOP; + q1->pcond = p; + } + + if(autoffset < StackBig) { // do we need to call morestack + if(autoffset <= StackSmall) { + // small stack + p = appendp(p); + p->as = ACMPL; + p->from.type = D_SP; + p->to.type = D_INDIR+D_CX; + } else { + // large stack + p = appendp(p); + p->as = ALEAL; + p->from.type = D_INDIR+D_SP; + p->from.offset = -(autoffset-StackSmall); + p->to.type = D_AX; + + p = appendp(p); + p->as = ACMPL; + p->from.type = D_AX; + p->to.type = D_INDIR+D_CX; + } + + // common + p = appendp(p); + p->as = AJHI; + p->to.type = D_BRANCH; + p->to.offset = 4; + q = p; + } + + p = appendp(p); // save frame size in DX + p->as = AMOVL; + p->to.type = D_DX; + /* 160 comes from 3 calls (3*8) 4 safes (4*8) and 104 guard */ + p->from.type = D_CONST; + if(autoffset+160+cursym->text->to.offset2 > 4096) + p->from.offset = (autoffset+160) & ~7LL; + + p = appendp(p); // save arg size in AX + p->as = AMOVL; + p->to.type = D_AX; + p->from.type = D_CONST; + p->from.offset = cursym->text->to.offset2; + + p = appendp(p); + p->as = ACALL; + p->to.type = D_BRANCH; + p->pcond = pmorestack; + p->to.sym = symmorestack; + } - } - if(curtext && curtext->from.sym) { - curtext->from.sym->frame = curframe; - curtext->from.sym->become = curbecome; - if(curbecome > maxbecome) - maxbecome = curbecome; - } - if(debug['b']) - print("max become = %d\n", maxbecome); - xdefine("ALEFbecome", STEXT, maxbecome); + if(q != P) + q->pcond = p->link; - curtext = 0; - for(p = firstp; p != P; p = p->link) { - switch(p->as) { - case ATEXT: - curtext = p; - break; - case ACALL: - if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) { - f = maxbecome - curtext->from.sym->frame; - if(f <= 0) - break; - /* calling a become or calling a variable */ - if(p->to.sym == S || p->to.sym->become) { - curtext->to.offset += f; - if(debug['b']) { - curp = p; - print("%D calling %D increase %d\n", - &curtext->from, &p->to, f); - } - } + if(autoffset) { + p = appendp(p); + p->as = AADJSP; + p->from.type = D_CONST; + p->from.offset = autoffset; + p->spadj = autoffset; + if(q != P) + q->pcond = p; + } + deltasp = autoffset; + + for(; p != P; p = p->link) { + a = p->from.type; + if(a == D_AUTO) + p->from.offset += deltasp; + if(a == D_PARAM) + p->from.offset += deltasp + 4; + a = p->to.type; + if(a == D_AUTO) + p->to.offset += deltasp; + if(a == D_PARAM) + p->to.offset += deltasp + 4; + + switch(p->as) { + default: + continue; + case APUSHL: + case APUSHFL: + deltasp += 4; + p->spadj = 4; + continue; + case APUSHW: + case APUSHFW: + deltasp += 2; + p->spadj = 2; + continue; + case APOPL: + case APOPFL: + deltasp -= 4; + p->spadj = -4; + continue; + case APOPW: + case APOPFW: + deltasp -= 2; + p->spadj = -2; + continue; + case ARET: + break; } - break; - } - } - - autoffset = 0; - deltasp = 0; - for(p = firstp; p != P; p = p->link) { - if(p->as == ATEXT) { - curtext = p; - autoffset = p->to.offset; - if(autoffset < 0) - autoffset = 0; + + if(autoffset != deltasp) + diag("unbalanced PUSH/POP"); + if(autoffset) { - p = appendp(p); p->as = AADJSP; p->from.type = D_CONST; - p->from.offset = autoffset; + p->from.offset = -autoffset; + p->spadj = -autoffset; + p = appendp(p); + p->as = ARET; + // If there are instructions following + // this ARET, they come from a branch + // with the same stackframe, so undo + // the cleanup. + p->spadj = +autoffset; } - deltasp = autoffset; } - a = p->from.type; - if(a == D_AUTO) - p->from.offset += deltasp; - if(a == D_PARAM) - p->from.offset += deltasp + 4; - a = p->to.type; - if(a == D_AUTO) - p->to.offset += deltasp; - if(a == D_PARAM) - p->to.offset += deltasp + 4; - - switch(p->as) { - default: - continue; - case APUSHL: - case APUSHFL: - deltasp += 4; - continue; - case APUSHW: - case APUSHFW: - deltasp += 2; - continue; - case APOPL: - case APOPFL: - deltasp -= 4; - continue; - case APOPW: - case APOPFW: - deltasp -= 2; - continue; - case ARET: - break; - } - - if(autoffset != deltasp) - diag("unbalanced PUSH/POP"); - if(p->from.type == D_CONST) - goto become; - - if(autoffset) { - q = p; - p = appendp(p); - p->as = ARET; - - q->as = AADJSP; - q->from.type = D_CONST; - q->from.offset = -autoffset; - } - continue; - - become: - q = p; - p = appendp(p); - p->as = AJMP; - p->to = q->to; - p->pcond = q->pcond; - - q->as = AADJSP; - q->from = zprg.from; - q->from.type = D_CONST; - q->from.offset = -autoffset; - q->to = zprg.to; - continue; } } -long +int32 atolwhex(char *s) { - long n; + int32 n; int f; n = 0; @@ -607,161 +658,3 @@ n = -n; return n; } - -void -undef(void) -{ - int i; - Sym *s; - - for(i=0; ilink) - if(s->type == SXREF) - diag("%s: not defined", s->name); -} - -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)){ - if(s->value != 0) - diag("value != 0 on SXREF"); - undefsym(s); - if(debug['X']) - Bprint(&bso, "IMPORT: %s sig=%lux v=%ld\n", s->name, s->sig, s->value); - if(debug['S']) - s->sig = 0; - } -} - -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(); - if(edatap == P) - datap = p; - else - edatap->link = p; - edatap = p; - p->as = ADATA; - p->width = w; - p->from.scale = w; - p->from.type = t; - p->from.sym = s; - p->from.offset = o; - p->to.type = D_CONST; - 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]; - if(debug['S']) - s->sig = 0; - /* 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.type = D_ADDR; - p->to.index = 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; - memmove(p->to.scon, buf, NSNAME); - nb = 0; - } - if(*t++ == 0) - break; - } - - /* name */ - p = newdata(et, off, sizeof(long), D_EXTERN); - off += sizeof(long); - p->to.type = D_ADDR; - p->to.index = 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; - memmove(p->to.scon, 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); -} diff -r d8d00747375b sys/src/cmd/8l/prof.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/src/cmd/8l/prof.c Mon Nov 14 17:35:25 2011 +0100 @@ -0,0 +1,173 @@ +// Inferno utils/8l/obj.c +// http://code.google.com/p/inferno-os/source/browse/utils/8l/obj.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. + +// Profiling. + +#include "l.h" +#include "../ld/lib.h" + +void +doprof1(void) +{ +#ifdef NOTDEF // TODO(rsc) + Sym *s; + int32 n; + Prog *p, *q; + + if(debug['v']) + Bprint(&bso, "%5.2f profile 1\n", cputime()); + Bflush(&bso); + s = lookup("__mcount", 0); + n = 1; + for(p = firstp->link; p != P; p = p->link) { + if(p->as == ATEXT) { + q = prg(); + q->line = p->line; + q->link = datap; + datap = q; + q->as = ADATA; + q->from.type = D_EXTERN; + q->from.offset = n*4; + q->from.sym = s; + q->from.scale = 4; + q->to = p->from; + q->to.type = D_CONST; + + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + p->as = AADDL; + p->from.type = D_CONST; + p->from.offset = 1; + p->to.type = D_EXTERN; + p->to.sym = s; + p->to.offset = n*4 + 4; + + n += 2; + continue; + } + } + q = prg(); + q->line = 0; + q->link = datap; + datap = q; + + q->as = ADATA; + q->from.type = D_EXTERN; + q->from.sym = s; + q->from.scale = 4; + q->to.type = D_CONST; + q->to.offset = n; + + s->type = SBSS; + s->size = n*4; +#endif +} + +void +doprof2(void) +{ + Sym *s2, *s4; + Prog *p, *q, *ps2, *ps4; + + if(debug['v']) + Bprint(&bso, "%5.2f profile 2\n", cputime()); + Bflush(&bso); + + s2 = lookup("_profin", 0); + s4 = lookup("_profout", 0); + if(s2->type != STEXT || s4->type != STEXT) { + diag("_profin/_profout not defined"); + return; + } + + ps2 = P; + ps4 = P; + for(cursym = textp; cursym != nil; cursym = cursym->next) { + p = cursym->text; + if(p->from.sym == s2) { + p->from.scale = 1; + ps2 = p; + } + if(p->from.sym == s4) { + p->from.scale = 1; + ps4 = p; + } + } + for(cursym = textp; cursym != nil; cursym = cursym->next) { + p = cursym->text; + + if(p->from.scale & NOPROF) /* dont profile */ + continue; + + /* + * JMPL profin + */ + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + p->as = ACALL; + p->to.type = D_BRANCH; + p->pcond = ps2; + p->to.sym = s2; + + for(; p; p=p->link) { + if(p->as == ARET) { + /* + * RET + */ + q = prg(); + q->as = ARET; + q->from = p->from; + q->to = p->to; + q->link = p->link; + p->link = q; + + /* + * JAL profout + */ + p->as = ACALL; + p->from = zprg.from; + p->to = zprg.to; + p->to.type = D_BRANCH; + p->pcond = ps4; + p->to.sym = s4; + + p = q; + } + } + } +} diff -r d8d00747375b sys/src/cmd/8l/span.c --- a/sys/src/cmd/8l/span.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/8l/span.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,25 +1,55 @@ +// Inferno utils/8l/span.c +// http://code.google.com/p/inferno-os/source/browse/utils/8l/span.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. + +// Instruction layout. + #include "l.h" +#include "../ld/lib.h" + +static int32 vaddr(Adr*, Reloc*); void -span(void) +span1(Sym *s) { Prog *p, *q; - long v, c, idat; - int m, n, again; + int32 c, v, loop; + uchar *bp; + int n, m, i; - xdefine("etext", STEXT, 0L); - idat = INITDAT; - for(p = firstp; p != P; p = p->link) { - if(p->as == ATEXT) - curtext = p; - n = 0; - if(p->to.type == D_BRANCH) - if(p->pcond == P) - p->pcond = p; - if((q = p->pcond) != P) - if(q->back != 2) - n = 1; - p->back = n; + cursym = s; + + for(p = s->text; p != P; p = p->link) { + p->back = 2; // use short branches first time through + if((q = p->pcond) != P && (q->back & 2)) + p->back |= 1; // backward jump + if(p->as == AADJSP) { p->to.type = D_SP; v = -p->from.offset; @@ -34,281 +64,215 @@ p->as = ANOP; } } + n = 0; + do { + loop = 0; + memset(s->r, 0, s->nr*sizeof s->r[0]); + s->nr = 0; + s->np = 0; + c = 0; + for(p = s->text; p != P; p = p->link) { + p->pc = c; -start: - if(debug['v']) - Bprint(&bso, "%5.2f span\n", cputime()); - Bflush(&bso); - c = INITTEXT; - for(p = firstp; p != P; p = p->link) { - if(p->as == ATEXT) - curtext = p; - if(p->to.type == D_BRANCH) - if(p->back) - p->pc = c; - asmins(p); - p->pc = c; - m = andptr-and; - p->mark = m; - c += m; - } + // process forward jumps to p + for(q = p->comefrom; q != P; q = q->forwd) { + v = p->pc - (q->pc + q->mark); + if(q->back & 2) { // short + if(v > 127) { + loop++; + q->back ^= 2; + } + if(q->as == AJCXZW) + s->p[q->pc+2] = v; + else + s->p[q->pc+1] = v; + } else { + bp = s->p + q->pc + q->mark - 4; + *bp++ = v; + *bp++ = v>>8; + *bp++ = v>>16; + *bp = v>>24; + } + } + p->comefrom = P; -loop: - n++; - if(debug['v']) - Bprint(&bso, "%5.2f span %d\n", cputime(), n); - Bflush(&bso); - if(n > 50) { - print("span must be looping\n"); - errorexit(); - } - again = 0; - c = INITTEXT; - for(p = firstp; p != P; p = p->link) { - if(p->as == ATEXT) - curtext = p; - if(p->to.type == D_BRANCH) { - if(p->back) - p->pc = c; asmins(p); + p->pc = c; m = andptr-and; - if(m != p->mark) { - p->mark = m; - again++; - } + symgrow(s, p->pc+m); + memmove(s->p+p->pc, and, m); + p->mark = m; + c += m; } - p->pc = c; - c += p->mark; - } - if(again) { - textsize = c; - goto loop; - } - if(INITRND) { - INITDAT = rnd(c, INITRND); - if(INITDAT != idat) { - idat = INITDAT; - goto start; + if(++n > 20) { + diag("span must be looping"); + errorexit(); + } + } while(loop); + s->size = c; + + if(debug['a'] > 1) { + print("span1 %s %d (%d tries)\n %.6ux", s->name, s->size, n, 0); + for(i=0; inp; i++) { + print(" %.2ux", s->p[i]); + if(i%16 == 15) + print("\n %.6ux", i+1); + } + if(i%16) + print("\n"); + + for(i=0; inr; i++) { + Reloc *r; + + r = &s->r[i]; + print(" rel %#.4ux/%d %s%+d\n", r->off, r->siz, r->sym->name, r->add); } } - xdefine("etext", STEXT, c); - if(debug['v']) - Bprint(&bso, "etext = %lux\n", c); - Bflush(&bso); - for(p = textp; p != P; p = p->pcond) - p->from.sym->value = p->pc; - textsize = c - INITTEXT; } void -xdefine(char *p, int t, long v) +span(void) +{ + Prog *p, *q; + int32 v; + int n; + + if(debug['v']) + Bprint(&bso, "%5.2f span\n", cputime()); + + // NOTE(rsc): If we get rid of the globals we should + // be able to parallelize these iterations. + for(cursym = textp; cursym != nil; cursym = cursym->next) { + if(cursym->text == nil || cursym->text->link == nil) + continue; + + // TODO: move into span1 + for(p = cursym->text; p != P; p = p->link) { + n = 0; + if(p->to.type == D_BRANCH) + if(p->pcond == P) + p->pcond = p; + if((q = p->pcond) != P) + if(q->back != 2) + n = 1; + p->back = n; + if(p->as == AADJSP) { + p->to.type = D_SP; + v = -p->from.offset; + p->from.offset = v; + p->as = AADDL; + if(v < 0) { + p->as = ASUBL; + v = -v; + p->from.offset = v; + } + if(v == 0) + p->as = ANOP; + } + } + span1(cursym); + } +} + +void +xdefine(char *p, int t, int32 v) { Sym *s; s = lookup(p, 0); - if(s->type == 0 || s->type == SXREF) { - s->type = t; - s->value = v; - } - if(s->type == STEXT && s->value == 0) - s->value = v; + s->type = t; + s->value = v; + s->reachable = 1; + s->special = 1; } void -putsymb(char *s, int t, long v, int ver) +instinit(void) { - int i, f; + int i; - if(t == 'f') - s++; - lput(v); - if(ver) - t += 'a' - 'A'; - cput(t+0x80); /* 0x80 is variable length */ + for(i=1; optab[i].as; i++) + if(i != optab[i].as) { + diag("phase error in optab: %d", i); + errorexit(); + } + maxop = i; - if(t == 'Z' || t == 'z') { - cput(s[0]); - for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) { - cput(s[i]); - cput(s[i+1]); - } - cput(0); - cput(0); - i++; - } - else { - for(i=0; s[i]; i++) - cput(s[i]); - cput(0); - } - symsize += 4 + 1 + i + 1; + for(i=0; i\n", t, v, s, ver); - else - Bprint(&bso, "%c %.8lux %s\n", t, v, s); + ycover[Yi0*Ymax + Yi8] = 1; + ycover[Yi1*Ymax + Yi8] = 1; + + ycover[Yi0*Ymax + Yi32] = 1; + ycover[Yi1*Ymax + Yi32] = 1; + ycover[Yi8*Ymax + Yi32] = 1; + + ycover[Yal*Ymax + Yrb] = 1; + ycover[Ycl*Ymax + Yrb] = 1; + ycover[Yax*Ymax + Yrb] = 1; + ycover[Ycx*Ymax + Yrb] = 1; + ycover[Yrx*Ymax + Yrb] = 1; + + ycover[Yax*Ymax + Yrx] = 1; + ycover[Ycx*Ymax + Yrx] = 1; + + ycover[Yax*Ymax + Yrl] = 1; + ycover[Ycx*Ymax + Yrl] = 1; + ycover[Yrx*Ymax + Yrl] = 1; + + ycover[Yf0*Ymax + Yrf] = 1; + + ycover[Yal*Ymax + Ymb] = 1; + ycover[Ycl*Ymax + Ymb] = 1; + ycover[Yax*Ymax + Ymb] = 1; + ycover[Ycx*Ymax + Ymb] = 1; + ycover[Yrx*Ymax + Ymb] = 1; + ycover[Yrb*Ymax + Ymb] = 1; + ycover[Ym*Ymax + Ymb] = 1; + + ycover[Yax*Ymax + Yml] = 1; + ycover[Ycx*Ymax + Yml] = 1; + ycover[Yrx*Ymax + Yml] = 1; + ycover[Yrl*Ymax + Yml] = 1; + ycover[Ym*Ymax + Yml] = 1; + + for(i=0; i= D_AL && i <= D_BH) + reg[i] = (i-D_AL) & 7; + if(i >= D_AX && i <= D_DI) + reg[i] = (i-D_AX) & 7; + if(i >= D_F0 && i <= D_F0+7) + reg[i] = (i-D_F0) & 7; } } -void -asmsym(void) +int +prefixof(Adr *a) { - Prog *p; - Auto *a; - Sym *s; - int h; - - s = lookup("etext", 0); - if(s->type == STEXT) - putsymb(s->name, 'T', s->value, s->version); - - for(h=0; hlink) - switch(s->type) { - case SCONST: - putsymb(s->name, 'D', s->value, s->version); - continue; - - case SDATA: - putsymb(s->name, 'D', s->value+INITDAT, s->version); - continue; - - case SBSS: - putsymb(s->name, 'B', s->value+INITDAT, s->version); - continue; - - case SFILE: - putsymb(s->name, 'f', s->value, s->version); - continue; - } - - for(p=textp; p!=P; p=p->pcond) { - s = p->from.sym; - if(s->type != STEXT) - continue; - - /* filenames first */ - for(a=p->to.autom; a; a=a->link) - if(a->type == D_FILE) - putsymb(a->asym->name, 'z', a->aoffset, 0); - else - if(a->type == D_FILE1) - putsymb(a->asym->name, 'Z', a->aoffset, 0); - - putsymb(s->name, 'T', s->value, s->version); - - /* frame, auto and param after */ - putsymb(".frame", 'm', p->to.offset+4, 0); - - for(a=p->to.autom; a; a=a->link) - if(a->type == D_AUTO) - putsymb(a->asym->name, 'a', -a->aoffset, 0); - else - if(a->type == D_PARAM) - putsymb(a->asym->name, 'p', a->aoffset, 0); + switch(a->type) { + case D_INDIR+D_CS: + return 0x2e; + case D_INDIR+D_DS: + return 0x3e; + case D_INDIR+D_ES: + return 0x26; + case D_INDIR+D_FS: + return 0x64; + case D_INDIR+D_GS: + return 0x65; } - if(debug['v'] || debug['n']) - Bprint(&bso, "symsize = %lud\n", symsize); - Bflush(&bso); -} - -void -asmlc(void) -{ - long oldpc, oldlc; - Prog *p; - long v, s; - - oldpc = INITTEXT; - oldlc = 0; - for(p = firstp; p != P; p = p->link) { - if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) { - if(p->as == ATEXT) - curtext = p; - if(debug['L']) - Bprint(&bso, "%6lux %P\n", - p->pc, p); - continue; - } - if(debug['L']) - Bprint(&bso, "\t\t%6ld", lcsize); - v = (p->pc - oldpc) / MINLC; - while(v) { - s = 127; - if(v < 127) - s = v; - cput(s+128); /* 129-255 +pc */ - if(debug['L']) - Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128); - v -= s; - lcsize++; - } - s = p->line - oldlc; - oldlc = p->line; - oldpc = p->pc + MINLC; - if(s > 64 || s < -64) { - cput(0); /* 0 vv +lc */ - cput(s>>24); - cput(s>>16); - cput(s>>8); - cput(s); - if(debug['L']) { - if(s > 0) - Bprint(&bso, " lc+%ld(%d,%ld)\n", - s, 0, s); - else - Bprint(&bso, " lc%ld(%d,%ld)\n", - s, 0, s); - Bprint(&bso, "%6lux %P\n", - p->pc, p); - } - lcsize += 5; - continue; - } - if(s > 0) { - cput(0+s); /* 1-64 +lc */ - if(debug['L']) { - Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s); - Bprint(&bso, "%6lux %P\n", - p->pc, p); - } - } else { - cput(64-s); /* 65-128 -lc */ - if(debug['L']) { - Bprint(&bso, " lc%ld(%ld)\n", s, 64-s); - Bprint(&bso, "%6lux %P\n", - p->pc, p); - } - } - lcsize++; - } - while(lcsize & 1) { - s = 129; - cput(s); - lcsize++; - } - if(debug['v'] || debug['L']) - Bprint(&bso, "lcsize = %ld\n", lcsize); - Bflush(&bso); + return 0; } int oclass(Adr *a) { - long v; + int32 v; - if(a->type >= D_INDIR || a->index != D_NONE) { + if((a->type >= D_INDIR && a->type < 2*D_INDIR) || a->index != D_NONE) { if(a->index != D_NONE && a->scale == 0) { if(a->type == D_ADDR) { switch(a->index) { @@ -321,6 +285,8 @@ } return Yxxx; } + //if(a->type == D_INDIR+D_ADDR) + // print("*Ycol\n"); return Ycol; } return Ym; @@ -417,6 +383,7 @@ return Ym; case D_CONST: + case D_CONST2: case D_ADDR: if(a->sym == S) { v = a->offset; @@ -436,11 +403,11 @@ } void -asmidx(Adr *a, int base) +asmidx(int scale, int index, int base) { int i; - switch(a->index) { + switch(index) { default: goto bad; @@ -455,10 +422,10 @@ case D_BP: case D_SI: case D_DI: - i = reg[a->index] << 3; + i = reg[index] << 3; break; } - switch(a->scale) { + switch(scale) { default: goto bad; case 1: @@ -494,18 +461,14 @@ *andptr++ = i; return; bad: - diag("asmidx: bad address %D", a); + diag("asmidx: bad address %d,%d,%d", scale, index, base); *andptr++ = 0; return; } static void -put4(long v) +put4(int32 v) { - if(dlm && curp != P && reloca != nil){ - dynreloc(reloca->sym, curp->pc + andptr - &and[0], 1); - reloca = nil; - } andptr[0] = v; andptr[1] = v>>8; andptr[2] = v>>16; @@ -513,12 +476,40 @@ andptr += 4; } -long -vaddr(Adr *a) +static void +relput4(Prog *p, Adr *a) +{ + vlong v; + Reloc rel, *r; + + v = vaddr(a, &rel); + if(rel.siz != 0) { + if(rel.siz != 4) + diag("bad reloc"); + r = addrel(cursym); + *r = rel; + r->off = p->pc + andptr - and; + } + put4(v); +} + +int32 +symaddr(Sym *s) +{ + if(!s->reachable) + diag("unreachable symbol in symaddr - %s", s->name); + return s->value; +} + +static int32 +vaddr(Adr *a, Reloc *r) { int t; - long v; + int32 v; Sym *s; + + if(r != nil) + memset(r, 0, sizeof *r); t = a->type; v = a->offset; @@ -529,18 +520,18 @@ case D_EXTERN: s = a->sym; if(s != nil) { - if(dlm && curp != P) - reloca = a; - switch(s->type) { - case SUNDEF: - ckoff(s, v); - case STEXT: - case SCONST: - v += s->value; - break; - default: - v += INITDAT + s->value; + if(!s->reachable) + sysfatal("unreachable symbol in vaddr - %s", s->name); + if(r == nil) { + diag("need reloc for %D", a); + errorexit(); } + r->type = D_ADDR; + r->siz = 4; + r->off = -1; + r->sym = s; + r->add = v; + v = 0; } } return v; @@ -549,54 +540,50 @@ void asmand(Adr *a, int r) { - long v; - int t; - Adr aa; + int32 v; + int t, scale; + Reloc rel; v = a->offset; t = a->type; + rel.siz = 0; if(a->index != D_NONE) { - if(t >= D_INDIR) { + if(t < D_INDIR || t >= 2*D_INDIR) { + switch(t) { + default: + goto bad; + case D_STATIC: + case D_EXTERN: + t = D_NONE; + v = vaddr(a, &rel); + break; + case D_AUTO: + case D_PARAM: + t = D_SP; + break; + } + } else t -= D_INDIR; - if(t == D_NONE) { - *andptr++ = (0 << 6) | (4 << 0) | (r << 3); - asmidx(a, t); - put4(v); - return; - } - if(v == 0 && t != D_BP) { - *andptr++ = (0 << 6) | (4 << 0) | (r << 3); - asmidx(a, t); - return; - } - if(v >= -128 && v < 128) { - *andptr++ = (1 << 6) | (4 << 0) | (r << 3); - asmidx(a, t); - *andptr++ = v; - return; - } - *andptr++ = (2 << 6) | (4 << 0) | (r << 3); - asmidx(a, t); - put4(v); + + if(t == D_NONE) { + *andptr++ = (0 << 6) | (4 << 0) | (r << 3); + asmidx(a->scale, a->index, t); + goto putrelv; + } + if(v == 0 && rel.siz == 0 && t != D_BP) { + *andptr++ = (0 << 6) | (4 << 0) | (r << 3); + asmidx(a->scale, a->index, t); return; } - switch(t) { - default: - goto bad; - case D_STATIC: - case D_EXTERN: - aa.type = D_NONE+D_INDIR; - break; - case D_AUTO: - case D_PARAM: - aa.type = D_SP+D_INDIR; - break; + if(v >= -128 && v < 128 && rel.siz == 0) { + *andptr++ = (1 << 6) | (4 << 0) | (r << 3); + asmidx(a->scale, a->index, t); + *andptr++ = v; + return; } - aa.offset = vaddr(a); - aa.index = a->index; - aa.scale = a->scale; - asmand(&aa, r); - return; + *andptr++ = (2 << 6) | (4 << 0) | (r << 3); + asmidx(a->scale, a->index, t); + goto putrelv; } if(t >= D_AL && t <= D_F0+7) { if(v) @@ -604,64 +591,77 @@ *andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3); return; } - if(t >= D_INDIR) { + + scale = a->scale; + if(t < D_INDIR || t >= 2*D_INDIR) { + switch(a->type) { + default: + goto bad; + case D_STATIC: + case D_EXTERN: + t = D_NONE; + v = vaddr(a, &rel); + break; + case D_AUTO: + case D_PARAM: + t = D_SP; + break; + } + scale = 1; + } else t -= D_INDIR; - if(t == D_NONE) { - *andptr++ = (0 << 6) | (5 << 0) | (r << 3); - put4(v); + + if(t == D_NONE || (D_CS <= t && t <= D_GS)) { + *andptr++ = (0 << 6) | (5 << 0) | (r << 3); + goto putrelv; + } + if(t == D_SP) { + if(v == 0 && rel.siz == 0) { + *andptr++ = (0 << 6) | (4 << 0) | (r << 3); + asmidx(scale, D_NONE, t); return; } - if(t == D_SP) { - if(v == 0) { - *andptr++ = (0 << 6) | (4 << 0) | (r << 3); - asmidx(a, D_SP); - return; - } - if(v >= -128 && v < 128) { - *andptr++ = (1 << 6) | (4 << 0) | (r << 3); - asmidx(a, D_SP); - *andptr++ = v; - return; - } - *andptr++ = (2 << 6) | (4 << 0) | (r << 3); - asmidx(a, D_SP); - put4(v); + if(v >= -128 && v < 128 && rel.siz == 0) { + *andptr++ = (1 << 6) | (4 << 0) | (r << 3); + asmidx(scale, D_NONE, t); + *andptr++ = v; return; } - if(t >= D_AX && t <= D_DI) { - if(v == 0 && t != D_BP) { - *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3); - return; - } - if(v >= -128 && v < 128) { - andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3); - andptr[1] = v; - andptr += 2; - return; - } - *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3); - put4(v); + *andptr++ = (2 << 6) | (4 << 0) | (r << 3); + asmidx(scale, D_NONE, t); + goto putrelv; + } + if(t >= D_AX && t <= D_DI) { + if(v == 0 && rel.siz == 0 && t != D_BP) { + *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3); return; } - goto bad; + if(v >= -128 && v < 128 && rel.siz == 0) { + andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3); + andptr[1] = v; + andptr += 2; + return; + } + *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3); + goto putrelv; } - switch(a->type) { - default: - goto bad; - case D_STATIC: - case D_EXTERN: - aa.type = D_NONE+D_INDIR; - break; - case D_AUTO: - case D_PARAM: - aa.type = D_SP+D_INDIR; - break; + goto bad; + +putrelv: + if(rel.siz != 0) { + Reloc *r; + + if(rel.siz != 4) { + diag("bad rel"); + goto bad; + } + r = addrel(cursym); + *r = rel; + r->off = curp->pc + andptr - and; } - aa.index = D_NONE; - aa.scale = 1; - aa.offset = vaddr(a); - asmand(&aa, r); + put4(v); return; + bad: diag("asmand: bad address %D", a); return; @@ -767,6 +767,7 @@ ASHRL, Ycol, Yml, 6, 0xac,0xad,0,0, /* extra imul */ + AIMULW, Yml, Yrl, 7, Pq,0xaf,0,0, AIMULL, Yml, Yrl, 7, Pm,0xaf,0,0, 0 }; @@ -794,21 +795,33 @@ if(debug['Q']) print("\n%P s/%R/%R/\n", p, from, to); - if(p->from.type == from) + if(p->from.type == from) { p->from.type = to; - if(p->to.type == from) + p->ft = 0; + } + if(p->to.type == from) { p->to.type = to; + p->tt = 0; + } - if(p->from.index == from) + if(p->from.index == from) { p->from.index = to; - if(p->to.index == from) + p->ft = 0; + } + if(p->to.index == from) { p->to.index = to; + p->tt = 0; + } from += D_INDIR; - if(p->from.type == from) + if(p->from.type == from) { p->from.type = to+D_INDIR; - if(p->to.type == from) + p->ft = 0; + } + if(p->to.type == from) { p->to.type = to+D_INDIR; + p->tt = 0; + } if(debug['Q']) print("%P\n", p); @@ -821,11 +834,27 @@ Prog *q, pp; uchar *t; int z, op, ft, tt; - long v; + int32 v, pre; + Reloc rel, *r; + Adr *a; + + curp = p; // TODO + pre = prefixof(&p->from); + if(pre) + *andptr++ = pre; + pre = prefixof(&p->to); + if(pre) + *andptr++ = pre; + + if(p->ft == 0) + p->ft = oclass(&p->from); + if(p->tt == 0) + p->tt = oclass(&p->to); + + ft = p->ft * Ymax; + tt = p->tt * Ymax; o = &optab[p->as]; - ft = oclass(&p->from) * Ymax; - tt = oclass(&p->to) * Ymax; t = o->ytab; if(t == 0) { diag("asmins: noproto %P", p); @@ -855,7 +884,7 @@ case Pb: /* botch */ break; } - v = vaddr(&p->from); + op = o->op[z]; switch(t[2]) { default: @@ -881,9 +910,11 @@ diag("asmins: Zaut sb type ADDR"); p->from.type = p->from.index; p->from.index = D_NONE; + p->ft = 0; asmand(&p->from, reg[p->to.type]); p->from.index = p->from.type; p->from.type = D_ADDR; + p->ft = 0; break; case Zm_o: @@ -902,90 +933,95 @@ break; case Zm_ibo: - v = vaddr(&p->to); *andptr++ = op; asmand(&p->from, o->op[z+1]); - *andptr++ = v; + *andptr++ = vaddr(&p->to, nil); break; case Zibo_m: *andptr++ = op; asmand(&p->to, o->op[z+1]); - *andptr++ = v; + *andptr++ = vaddr(&p->from, nil); break; case Z_ib: - v = vaddr(&p->to); case Zib_: + if(t[2] == Zib_) + a = &p->from; + else + a = &p->to; + v = vaddr(a, nil); *andptr++ = op; *andptr++ = v; break; case Zib_rp: *andptr++ = op + reg[p->to.type]; - *andptr++ = v; + *andptr++ = vaddr(&p->from, nil); break; case Zil_rp: *andptr++ = op + reg[p->to.type]; if(o->prefix == Pe) { + v = vaddr(&p->from, nil); *andptr++ = v; *andptr++ = v>>8; } else - put4(v); + relput4(p, &p->from); break; case Zib_rr: *andptr++ = op; asmand(&p->to, reg[p->to.type]); - *andptr++ = v; + *andptr++ = vaddr(&p->from, nil); break; case Z_il: - v = vaddr(&p->to); case Zil_: + if(t[2] == Zil_) + a = &p->from; + else + a = &p->to; *andptr++ = op; if(o->prefix == Pe) { + v = vaddr(a, nil); *andptr++ = v; *andptr++ = v>>8; } else - put4(v); + relput4(p, a); break; case Zm_ilo: - v = vaddr(&p->to); + case Zilo_m: *andptr++ = op; - asmand(&p->from, o->op[z+1]); + if(t[2] == Zilo_m) { + a = &p->from; + asmand(&p->to, o->op[z+1]); + } else { + a = &p->to; + asmand(&p->from, o->op[z+1]); + } if(o->prefix == Pe) { + v = vaddr(a, nil); *andptr++ = v; *andptr++ = v>>8; } else - put4(v); - break; - - case Zilo_m: - *andptr++ = op; - asmand(&p->to, o->op[z+1]); - if(o->prefix == Pe) { - *andptr++ = v; - *andptr++ = v>>8; - } - else - put4(v); + relput4(p, a); break; case Zil_rr: *andptr++ = op; asmand(&p->to, reg[p->to.type]); if(o->prefix == Pe) { + v = vaddr(&p->from, nil); *andptr++ = v; *andptr++ = v>>8; } else - put4(v); + relput4(p, &p->from); break; case Z_rp: @@ -1000,75 +1036,136 @@ *andptr++ = op; asmand(&p->to, reg[p->to.type]); break; + + case Zcall: + q = p->pcond; + if(q == nil) { + diag("call without target"); + errorexit(); + } + if(q->as != ATEXT) { + // Could handle this case by making D_PCREL + // record the Prog* instead of the Sym*, but let's + // wait until the need arises. + diag("call of non-TEXT %P", q); + errorexit(); + } + *andptr++ = op; + r = addrel(cursym); + r->off = p->pc + andptr - and; + r->type = D_PCREL; + r->siz = 4; + r->sym = q->from.sym; + put4(0); + break; case Zbr: + case Zjmp: + case Zloop: q = p->pcond; - if(q) { - v = q->pc - p->pc - 2; - if(v >= -128 && v <= 127) { + if(q == nil) { + diag("jmp/branch/loop without target"); + errorexit(); + } + if(q->as == ATEXT) { + // jump out of function + if(t[2] == Zbr) { + diag("branch to ATEXT"); + errorexit(); + } + *andptr++ = o->op[z+1]; + r = addrel(cursym); + r->off = p->pc + andptr - and; + r->sym = q->from.sym; + r->type = D_PCREL; + r->siz = 4; + put4(0); + break; + } + + // Assumes q is in this function. + // TODO: Check in input, preserve in brchain. + + // Fill in backward jump now. + if(p->back & 1) { + v = q->pc - (p->pc + 2); + if(v >= -128) { + if(p->as == AJCXZW) + *andptr++ = 0x67; *andptr++ = op; *andptr++ = v; + } else if(t[2] == Zloop) { + diag("loop too far: %P", p); } else { - v -= 6-2; - *andptr++ = 0x0f; + v -= 5-2; + if(t[2] == Zbr) { + *andptr++ = 0x0f; + v--; + } *andptr++ = o->op[z+1]; *andptr++ = v; *andptr++ = v>>8; *andptr++ = v>>16; *andptr++ = v>>24; } + break; + } + + // Annotate target; will fill in later. + p->forwd = q->comefrom; + q->comefrom = p; + if(p->back & 2) { // short + if(p->as == AJCXZW) + *andptr++ = 0x67; + *andptr++ = op; + *andptr++ = 0; + } else if(t[2] == Zloop) { + diag("loop too far: %P", p); + } else { + if(t[2] == Zbr) + *andptr++ = 0x0f; + *andptr++ = o->op[z+1]; + *andptr++ = 0; + *andptr++ = 0; + *andptr++ = 0; + *andptr++ = 0; } break; - case Zcall: - q = p->pcond; - if(q) { - v = q->pc - p->pc - 5; - if(dlm && curp != P && p->to.sym->type == SUNDEF){ - /* v = 0 - p->pc - 5; */ - v = 0; - ckoff(p->to.sym, v); - v += p->to.sym->value; - dynreloc(p->to.sym, p->pc+1, 0); - } + case Zcallcon: + case Zjmpcon: + if(t[2] == Zcallcon) *andptr++ = op; - *andptr++ = v; - *andptr++ = v>>8; - *andptr++ = v>>16; - *andptr++ = v>>24; - } + else + *andptr++ = o->op[z+1]; + r = addrel(cursym); + r->off = p->pc + andptr - and; + r->type = D_PCREL; + r->siz = 4; + r->add = p->to.offset; + put4(0); break; - - case Zjmp: - q = p->pcond; - if(q) { - v = q->pc - p->pc - 2; - if(v >= -128 && v <= 127) { - *andptr++ = op; - *andptr++ = v; - } else { - v -= 5-2; - *andptr++ = o->op[z+1]; - *andptr++ = v; - *andptr++ = v>>8; - *andptr++ = v>>16; - *andptr++ = v>>24; - } - } - break; - - case Zloop: - q = p->pcond; - if(q) { - v = q->pc - p->pc - 2; - if(v < -128 && v > 127) - diag("loop too far: %P", p); - *andptr++ = op; - *andptr++ = v; - } + + case Zcallind: + *andptr++ = op; + *andptr++ = o->op[z+1]; + r = addrel(cursym); + r->off = p->pc + andptr - and; + r->type = D_ADDR; + r->siz = 4; + r->add = p->to.offset; + r->sym = p->to.sym; + put4(0); break; case Zbyte: + v = vaddr(&p->from, &rel); + if(rel.siz != 0) { + rel.siz = op; + r = addrel(cursym); + *r = rel; + r->off = p->pc + andptr - and; + } *andptr++ = v; if(op > 1) { *andptr++ = v>>8; @@ -1218,7 +1315,11 @@ break; case 7: /* imul rm,r */ - *andptr++ = t[4]; + if(t[4] == Pq) { + *andptr++ = Pe; + *andptr++ = Pm; + } else + *andptr++ = t[4]; *andptr++ = t[5]; asmand(&p->from, reg[p->to.type]); break; @@ -1228,160 +1329,10 @@ void asmins(Prog *p) { - andptr = and; doasm(p); -} - -enum{ - ABSD = 0, - ABSU = 1, - RELD = 2, - RELU = 3, -}; - -int modemap[4] = { 0, 1, -1, 2, }; - -typedef struct Reloc Reloc; - -struct Reloc -{ - int n; - int t; - uchar *m; - ulong *a; -}; - -Reloc rels; - -static void -grow(Reloc *r) -{ - int t; - uchar *m, *nm; - ulong *a, *na; - - t = r->t; - r->t += 64; - m = r->m; - a = r->a; - r->m = nm = malloc(r->t*sizeof(uchar)); - r->a = na = malloc(r->t*sizeof(ulong)); - memmove(nm, m, t*sizeof(uchar)); - memmove(na, a, t*sizeof(ulong)); - free(m); - free(a); -} - -void -dynreloc(Sym *s, ulong v, int abs) -{ - int i, k, n; - uchar *m; - ulong *a; - Reloc *r; - - if(s->type == SUNDEF) - k = abs ? ABSU : RELU; - else - k = abs ? ABSD : RELD; - /* Bprint(&bso, "R %s a=%ld(%lx) %d\n", s->name, v, v, k); */ - k = modemap[k]; - r = &rels; - n = r->n; - if(n >= r->t) - grow(r); - m = r->m; - a = r->a; - for(i = n; i > 0; i--){ - if(v < a[i-1]){ /* happens occasionally for data */ - m[i] = m[i-1]; - a[i] = a[i-1]; - } - else - break; - } - m[i] = k; - a[i] = v; - r->n++; -} - -static int -sput(char *s) -{ - char *p; - - p = s; - while(*s) - cput(*s++); - cput(0); - return s-p+1; -} - -void -asmdyn() -{ - int i, n, t, c; - Sym *s; - ulong la, ra, *a; - vlong off; - uchar *m; - Reloc *r; - - cflush(); - off = seek(cout, 0, 1); - lput(0); - t = 0; - lput(imports); - t += 4; - for(i = 0; i < NHASH; i++) - for(s = hash[i]; s != S; s = s->link) - if(s->type == SUNDEF){ - lput(s->sig); - t += 4; - t += sput(s->name); - } - - la = 0; - r = &rels; - n = r->n; - m = r->m; - a = r->a; - lput(n); - t += 4; - for(i = 0; i < n; i++){ - ra = *a-la; - if(*a < la) - diag("bad relocation order"); - if(ra < 256) - c = 0; - else if(ra < 65536) - c = 1; - else - c = 2; - cput((c<<6)|*m++); - t++; - if(c == 0){ - cput(ra); - t++; - } - else if(c == 1){ - wput(ra); - t += 2; - } - else{ - lput(ra); - t += 4; - } - la = *a++; - } - - cflush(); - seek(cout, off, 0); - lput(t); - - if(debug['v']){ - Bprint(&bso, "import table entries = %d\n", imports); - Bprint(&bso, "export table entries = %d\n", exports); + if(andptr > and+sizeof and) { + print("and[] is too short - %ld byte instruction\n", andptr - and); + errorexit(); } } diff -r d8d00747375b sys/src/cmd/cc/acid.c --- a/sys/src/cmd/cc/acid.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/cc/acid.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,8 +1,39 @@ +// Inferno utils/cc/acid.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/acid.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 #include "cc.h" static char *kwd[] = { - "$adt", "$aggr", "$append", "$builtin", "$complex", "$defn", + "$adt", "$aggr", "$append", "$complex", "$defn", "$delete", "$do", "$else", "$eval", "$head", "$if", "$local", "$loop", "$return", "$tail", "$then", "$union", "$whatis", "$while", @@ -90,11 +121,13 @@ if(types[TINT]->width != types[TSHORT]->width) warn(Z, "acidmember int not long or short"); } + if(types[TIND]->width == types[TUVLONG]->width) + acidchar[TIND] = 'Y'; } void -acidmember(Type *t, long off, int flag) +acidmember(Type *t, int32 off, int flag) { Sym *s, *s1; Type *l; @@ -113,22 +146,31 @@ case TIND: if(s == S) break; - if(flag) { - for(l=t; l->etype==TIND; l=l->link) - ; + l = t->link; + if(flag) { if(typesu[l->etype]) { s1 = acidsue(l->link); if(s1 != S) { - Bprint(&outbuf, " 'A' %s %ld %s;\n", + Bprint(&outbuf, " 'A' %s %d %s;\n", amap(s1->name), t->offset+off, amap(s->name)); break; } } } else { - Bprint(&outbuf, - "\tprint(\"\t%s\t\", addr.%s\\X, \"\\n\");\n", - amap(s->name), amap(s->name)); + l = t->link; + s1 = S; + if(typesu[l->etype]) + s1 = acidsue(l->link); + if(s1 != S) { + Bprint(&outbuf, + "\tprint(indent, \"%s\t(%s)\", addr.%s\\X, \"\\n\");\n", + amap(s->name), amap(s1->name), amap(s->name)); + } else { + Bprint(&outbuf, + "\tprint(indent, \"%s\t\", addr.%s\\X, \"\\n\");\n", + amap(s->name), amap(s->name)); + } break; } @@ -148,10 +190,10 @@ if(s == S) break; if(flag) { - Bprint(&outbuf, " '%c' %ld %s;\n", + Bprint(&outbuf, " '%c' %d %s;\n", acidchar[t->etype], t->offset+off, amap(s->name)); } else { - Bprint(&outbuf, "\tprint(\"\t%s\t\", addr.%s, \"\\n\");\n", + Bprint(&outbuf, "\tprint(indent, \"%s\t\", addr.%s, \"\\n\");\n", amap(s->name), amap(s->name)); } break; @@ -168,23 +210,23 @@ acidmember(l, t->offset+off, flag); Bprint(&outbuf, " };\n"); } else { - Bprint(&outbuf, " %s %ld %s;\n", + Bprint(&outbuf, " %s %d %s;\n", amap(s1->name), t->offset+off, amap(s->name)); } } else { if(s != S) { - Bprint(&outbuf, "\tprint(\"%s %s {\\n\");\n", + Bprint(&outbuf, "\tprint(indent, \"%s %s {\\n\");\n", amap(s1->name), amap(s->name)); - Bprint(&outbuf, "\t%s(addr.%s);\n", + Bprint(&outbuf, "\tindent_%s(addr.%s, indent+\"\\t\");\n", amap(s1->name), amap(s->name)); - Bprint(&outbuf, "\tprint(\"}\\n\");\n"); + Bprint(&outbuf, "\tprint(indent, \"}\\n\");\n"); } else { - Bprint(&outbuf, "\tprint(\"%s {\\n\");\n", + Bprint(&outbuf, "\tprint(indent, \"%s {\\n\");\n", amap(s1->name)); - Bprint(&outbuf, "\t\t%s(addr+%ld);\n", + Bprint(&outbuf, "\tindent_%s(addr+%d, indent+\"\\t\");\n", amap(s1->name), t->offset+off); - Bprint(&outbuf, "\tprint(\"}\\n\");\n"); + Bprint(&outbuf, "\tprint(indent, \"}\\n\");\n"); } } break; @@ -222,13 +264,14 @@ if(debug['s']) goto asmstr; an = amap(s->name); - Bprint(&outbuf, "sizeof%s = %ld;\n", an, t->width); + Bprint(&outbuf, "sizeof%s = %d;\n", an, t->width); Bprint(&outbuf, "aggr %s\n{\n", an); for(l = t->link; l != T; l = l->down) acidmember(l, 0, 1); Bprint(&outbuf, "};\n\n"); - Bprint(&outbuf, "defn\n%s(addr) {\n\tcomplex %s addr;\n", an, an); + Bprint(&outbuf, "defn\n%s(addr) {\n\tindent_%s(addr, \"\\t\");\n}\n", an, an); + Bprint(&outbuf, "defn\nindent_%s(addr, indent) {\n\tcomplex %s addr;\n", an, an); for(l = t->link; l != T; l = l->down) acidmember(l, 0, 0); Bprint(&outbuf, "};\n\n"); @@ -238,7 +281,7 @@ break; for(l = t->link; l != T; l = l->down) if(l->sym != S) - Bprint(&outbuf, "#define\t%s.%s\t%ld\n", + Bprint(&outbuf, "#define\t%s.%s\t%d\n", s->name, l->sym->name, l->offset); diff -r d8d00747375b sys/src/cmd/cc/bits.c --- a/sys/src/cmd/cc/bits.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/cc/bits.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,3 +1,34 @@ +// Inferno utils/cc/bits.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/bits.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 #include "cc.h" Bits @@ -61,7 +92,7 @@ bnum(Bits a) { int i; - long b; + int32 b; for(i=0; i +// Inferno utils/cc/cc.h +// http://code.google.com/p/inferno-os/source/browse/utils/cc/cc.h +// +// 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 #include -#include #pragma lib "../cc/cc.a$O" @@ -9,6 +37,13 @@ #define EXTERN extern #endif +#undef getc +#undef ungetc +#undef BUFSIZ + +#define getc ccgetc +#define ungetc ccungetc + typedef struct Node Node; typedef struct Sym Sym; typedef struct Type Type; @@ -19,8 +54,9 @@ typedef struct Term Term; typedef struct Init Init; typedef struct Bits Bits; +typedef struct Dynimp Dynimp; +typedef struct Dynexp Dynexp; -#define NHUNK 50000L #define BUFSIZ 8192 #define NSYMB 500 #define NHASH 1024 @@ -30,14 +66,14 @@ #define NTERM 10 #define MAXALIGN 7 -#define SIGN(n) ((vlong)1<<(n-1)) +#define SIGN(n) ((uvlong)1<<(n-1)) #define MASK(n) (SIGN(n)|(SIGN(n)-1)) #define BITS 5 -#define NVAR (BITS*sizeof(ulong)*8) +#define NVAR (BITS*sizeof(uint32)*8) struct Bits { - ulong b[BITS]; + uint32 b[BITS]; }; struct Node @@ -45,9 +81,9 @@ Node* left; Node* right; void* label; - long pc; + int32 pc; int reg; - long xoffset; + int32 xoffset; double fconst; /* fp constant */ vlong vconst; /* non fp const */ char* cstring; /* character string */ @@ -55,16 +91,16 @@ Sym* sym; Type* type; - long lineno; - char op; - char oldop; - char xcast; - char class; - char etype; - char complex; - char addable; - char scale; - char garb; + int32 lineno; + uchar op; + uchar oldop; + uchar xcast; + uchar class; + uchar etype; + uchar complex; + uchar addable; + uchar scale; + uchar garb; }; #define Z ((Node*)0) @@ -75,8 +111,8 @@ Type* suetag; Type* tenum; char* macro; - long varlineno; - long offset; + int32 varlineno; + int32 offset; vlong vconst; double fconst; Node* label; @@ -84,10 +120,10 @@ char *name; ushort block; ushort sueblock; - char class; - char sym; - char aused; - char sig; + uchar class; + uchar sym; + uchar aused; + uchar sig; }; #define S ((Sym*)0) @@ -104,12 +140,12 @@ Decl* link; Sym* sym; Type* type; - long varlineno; - long offset; + int32 varlineno; + int32 offset; short val; ushort block; - char class; - char aused; + uchar class; + uchar aused; }; #define D ((Decl*)0) @@ -120,13 +156,14 @@ Funct* funct; Type* link; Type* down; - long width; - long offset; - long lineno; - schar shift; - char nbits; - char etype; - char garb; + int32 width; + int32 offset; + int32 lineno; + uchar shift; + uchar nbits; + uchar etype; + uchar garb; + uchar align; }; #define T ((Type*)0) @@ -135,7 +172,7 @@ struct Init /* general purpose initialization */ { int code; - ulong value; + uint32 value; char* s; }; @@ -159,8 +196,8 @@ { Hist* link; char* name; - long line; - long offset; + int32 line; + int32 offset; }; #define H ((Hist*)0) EXTERN Hist* hist; @@ -184,13 +221,6 @@ NALIGN, }; -enum /* also in ../{8a,0a}.h */ -{ - Plan9 = 1<<0, - Unix = 1<<1, - Windows = 1<<2, -}; - enum { DMARK, @@ -238,6 +268,7 @@ ODWHILE, OENUM, OEQ, + OEXREG, OFOR, OFUNC, OGE, @@ -319,7 +350,6 @@ TSTRUCT, TUNION, TENUM, - TDOT, NTYPE, TAUTO = NTYPE, @@ -332,6 +362,7 @@ TVOLATILE, TUNSIGNED, TSIGNED, + TDOT, TFILE, TOLD, NALLTYPES, @@ -412,6 +443,25 @@ Sym* castfr[NTYPE]; }; +struct Dynimp +{ + char* local; + char* remote; + char* path; +}; + +EXTERN Dynimp *dynimp; +EXTERN int ndynimp; + +struct Dynexp +{ + char* local; + char* remote; +}; + +EXTERN Dynexp *dynexp; +EXTERN int ndynexp; + EXTERN struct { Type* tenum; /* type of entire enum */ @@ -421,45 +471,45 @@ } en; EXTERN int autobn; -EXTERN long autoffset; +EXTERN int32 autoffset; EXTERN int blockno; EXTERN Decl* dclstack; EXTERN char debug[256]; EXTERN Hist* ehist; -EXTERN long firstbit; +EXTERN int32 firstbit; EXTERN Sym* firstarg; EXTERN Type* firstargtype; EXTERN Decl* firstdcl; EXTERN int fperror; EXTERN Sym* hash[NHASH]; -EXTERN int hasdoubled; EXTERN char* hunk; -EXTERN char* include[20]; +EXTERN char** include; EXTERN Io* iofree; EXTERN Io* ionext; EXTERN Io* iostack; -EXTERN long lastbit; +EXTERN int32 lastbit; EXTERN char lastclass; EXTERN Type* lastdcl; -EXTERN long lastfield; +EXTERN int32 lastfield; EXTERN Type* lasttype; -EXTERN long lineno; -EXTERN long nearln; +EXTERN int32 lineno; +EXTERN int32 nearln; EXTERN int nerrors; EXTERN int newflag; -EXTERN long nhunk; +EXTERN int32 nhunk; EXTERN int ninclude; EXTERN Node* nodproto; EXTERN Node* nodcast; +EXTERN int32 nsymb; EXTERN Biobuf outbuf; EXTERN Biobuf diagbuf; EXTERN char* outfile; EXTERN char* pathname; EXTERN int peekc; -EXTERN long stkoff; +EXTERN int32 stkoff; EXTERN Type* strf; EXTERN Type* strl; -EXTERN char symb[NSYMB]; +EXTERN char* symb; EXTERN Sym* symstring; EXTERN int taggen; EXTERN Type* tfield; @@ -467,7 +517,7 @@ EXTERN int thechar; EXTERN char* thestring; EXTERN Type* thisfn; -EXTERN long thunk; +EXTERN int32 thunk; EXTERN Type* types[NTYPE]; EXTERN Type* fntypes[NTYPE]; EXTERN Node* initlist; @@ -475,7 +525,7 @@ EXTERN int nterm; EXTERN int packflg; EXTERN int fproundflg; -EXTERN int profileflg; +EXTERN int textflag; EXTERN int ncontin; EXTERN int canreach; EXTERN int warnreach; @@ -483,52 +533,43 @@ extern char *onames[], *tnames[], *gnames[]; extern char *cnames[], *qnames[], *bnames[]; -extern char tab[NTYPE][NTYPE]; -extern char comrel[], invrel[], logrel[]; -extern long ncast[], tadd[], tand[]; -extern long targ[], tasadd[], tasign[], tcast[]; -extern long tdot[], tfunct[], tindir[], tmul[]; -extern long tnot[], trel[], tsub[]; +extern uchar tab[NTYPE][NTYPE]; +extern uchar comrel[], invrel[], logrel[]; +extern int32 ncast[], tadd[], tand[]; +extern int32 targ[], tasadd[], tasign[], tcast[]; +extern int32 tdot[], tfunct[], tindir[], tmul[]; +extern int32 tnot[], trel[], tsub[]; -extern char typeaf[]; -extern char typefd[]; -extern char typei[]; -extern char typesu[]; -extern char typesuv[]; -extern char typeu[]; -extern char typev[]; -extern char typec[]; -extern char typeh[]; -extern char typeil[]; -extern char typeilp[]; -extern char typechl[]; -extern char typechlv[]; -extern char typechlvp[]; -extern char typechlp[]; -extern char typechlpfd[]; +extern uchar typeaf[]; +extern uchar typefd[]; +extern uchar typei[]; +extern uchar typesu[]; +extern uchar typesuv[]; +extern uchar typeu[]; +extern uchar typev[]; +extern uchar typec[]; +extern uchar typeh[]; +extern uchar typeil[]; +extern uchar typeilp[]; +extern uchar typechl[]; +extern uchar typechlv[]; +extern uchar typechlvp[]; +extern uchar typechlp[]; +extern uchar typechlpfd[]; -EXTERN char* typeword; -EXTERN char* typecmplx; +EXTERN uchar* typeword; +EXTERN uchar* typecmplx; -extern ulong thash1; -extern ulong thash2; -extern ulong thash3; -extern ulong thash[]; +extern uint32 thash1; +extern uint32 thash2; +extern uint32 thash3; +extern uint32 thash[]; /* * compat.c/unix.c/windows.c */ -int mywait(int*); -int mycreat(char*, int); int systemtype(int); int pathchar(void); -int myaccess(char*); -char* mygetwd(char*, int); -int myexec(char*, char*[]); -int mydup(int, int); -int myfork(void); -int mypipe(int*); -void* mysbrk(ulong); /* * parser @@ -539,25 +580,26 @@ /* * lex.c */ -void* allocn(void*, long, long); -void* alloc(long); +void* allocn(void*, int32, int32); +void* alloc(int32); +void ensuresymb(int32); void cinit(void); int compile(char*, char**, int); void errorexit(void); int filbuf(void); int getc(void); -long getr(void); +int32 getr(void); int getnsc(void); Sym* lookup(void); void main(int, char*[]); void newfile(char*, int); void newio(void); void pushio(void); -long escchar(long, int, int); +int32 escchar(int32, int, int); Sym* slookup(char*); void syminit(Sym*); void unget(int); -long yylex(void); +int32 yylex(void); int Lconv(Fmt*); int Tconv(Fmt*); int FNconv(Fmt*); @@ -572,7 +614,7 @@ void dodefine(char*); void domacro(void); Sym* getsym(void); -long getnsn(void); +int32 getnsn(void); void linehist(char*, int); void macdef(void); void macprag(void); @@ -586,9 +628,9 @@ /* * dcl.c */ -Node* doinit(Sym*, Type*, long, Node*); +Node* doinit(Sym*, Type*, int32, Node*); Type* tcopy(Type*); -Node* init1(Sym*, Type*, long, int); +Node* init1(Sym*, Type*, int32, int); Node* newlist(Node*, Node*); void adecl(int, Type*, Sym*); int anyproto(Node*); @@ -609,16 +651,16 @@ Decl* push(void); Decl* push1(Sym*); Node* revertdcl(void); -long round(long, int); +int32 xround(int32, int); int rsametype(Type*, Type*, int, int); int sametype(Type*, Type*); -ulong sign(Sym*); -ulong signature(Type*); -void suallign(Type*); +uint32 sign(Sym*); +uint32 signature(Type*); +void sualign(Type*); void tmerge(Type*, Sym*); void walkparam(Node*, int); void xdecl(int, Type*, Sym*); -Node* contig(Sym*, Node*, long); +Node* contig(Sym*, Node*, int32); /* * com.c @@ -655,12 +697,12 @@ */ void arith(Node*, int); int deadheads(Node*); -Type* dotsearch(Sym*, Type*, Node*, long*); -long dotoffset(Type*, Type*, Node*); +Type* dotsearch(Sym*, Type*, Node*, int32*); +int32 dotoffset(Type*, Type*, Node*); void gethunk(void); Node* invert(Node*); -int bitno(long); -void makedot(Node*, Type*, long); +int bitno(int32); +void makedot(Node*, Type*, int32); int mixedasop(Type*, Type*); Node* new(int, Node*, Node*); Node* new1(int, Node*, Node*); @@ -670,12 +712,12 @@ void prtree1(Node*, int, int); void relcon(Node*, Node*); int relindex(int); -int simpleg(long); -Type* garbt(Type*, long); -int simplec(long); -Type* simplet(long); -int stcompat(Node*, Type*, Type*, long[]); -int tcompat(Node*, Type*, Type*, long[]); +int simpleg(int32); +Type* garbt(Type*, int32); +int simplec(int32); +Type* simplet(int32); +int stcompat(Node*, Type*, Type*, int32[]); +int tcompat(Node*, Type*, Type*, int32[]); void tinit(void); Type* typ(int, Type*); Type* copytyp(Type*); @@ -683,11 +725,11 @@ void typeext1(Type*, Node*); int side(Node*); int vconst(Node*); -int log2(uvlong); +int xlog2(uvlong); int vlog(Node*); -int topbit(ulong); +int topbit(uint32); void simplifyshift(Node*); -long typebitor(long, long); +int32 typebitor(int32, int32); void diag(Node*, char*, ...); void warn(Node*, char*, ...); void yyerror(char*, ...); @@ -700,9 +742,11 @@ void acidvar(Sym*); /* - * pickle.c + * godefs.c */ -void pickletype(Type*); +int Uconv(Fmt*); +void godeftype(Type*); +void godefvar(Sym*); /* * bits.c @@ -724,23 +768,25 @@ void pragvararg(void); void pragpack(void); void pragfpround(void); -void pragprofile(void); +void pragtextflag(void); void pragincomplete(void); +void pragdynimport(void); +void pragdynexport(void); /* * calls to machine depend part */ void codgen(Node*, Node*); void gclean(void); -void gextern(Sym*, Node*, long, long); +void gextern(Sym*, Node*, int32, int32); void ginit(void); -long outstring(char*, long); -long outlstring(ushort*, long); -void sextern(Sym*, Node*, long, long); +int32 outstring(char*, int32); +int32 outlstring(ushort*, int32); +void sextern(Sym*, Node*, int32, int32); void xcom(Node*); -long exreg(Type*); -long align(long, Type*, int); -long maxround(long, long); +int32 exreg(Type*); +int32 align(int32, Type*, int, int32*); +int32 maxround(int32, int32); extern schar ewidth[]; @@ -765,8 +811,21 @@ #pragma varargck argpos yyerror 1 #pragma varargck type "F" Node* -#pragma varargck type "L" long -#pragma varargck type "Q" long +#pragma varargck type "L" int32 +#pragma varargck type "Q" int32 #pragma varargck type "O" int +#pragma varargck type "O" uint #pragma varargck type "T" Type* +#pragma varargck type "U" char* #pragma varargck type "|" int + +enum +{ + Plan9 = 1<<0, + Unix = 1<<1, + Windows = 1<<2, +}; +int pathchar(void); +int systemtype(int); +void* alloc(int32 n); +void* allocn(void*, int32, int32); diff -r d8d00747375b sys/src/cmd/cc/cc.y --- a/sys/src/cmd/cc/cc.y Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/cc/cc.y Mon Nov 14 17:35:25 2011 +0100 @@ -1,4 +1,36 @@ +// Inferno utils/cc/cc.y +// http://code.google.com/p/inferno-os/source/browse/utils/cc/cc.y +// +// 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 +#include /* if we don't, bison will, and cc.h re-#defines getc */ #include "cc.h" %} %union { @@ -8,19 +40,21 @@ struct { Type* t; - char c; + uchar c; } tycl; struct { Type* t1; Type* t2; + Type* t3; + uchar c; } tyty; struct { char* s; - long l; + int32 l; } sval; - long lval; + int32 lval; double dval; vlong vval; } @@ -168,7 +202,7 @@ } '=' init { - long w; + int32 w; w = $1->sym->type->width; $$ = doinit($1->sym, $1->type, 0L, $4); @@ -895,16 +929,22 @@ { $$.t1 = strf; $$.t2 = strl; + $$.t3 = lasttype; + $$.c = lastclass; strf = T; strl = T; lastbit = 0; firstbit = 1; + lastclass = CXXX; + lasttype = T; } edecl '}' { $$ = strf; strf = $2.t1; strl = $2.t2; + lasttype = $2.t3; + lastclass = $2.c; } zctlist: @@ -995,7 +1035,7 @@ if($$->link != T) diag(Z, "redeclare tag: %s", $2->name); $$->link = $4; - suallign($$); + sualign($$); } | LSTRUCT sbody { @@ -1003,7 +1043,7 @@ sprint(symb, "_%d_", taggen); $$ = dotag(lookup(), TSTRUCT, autobn); $$->link = $2; - suallign($$); + sualign($$); } | LUNION ltag { @@ -1020,7 +1060,7 @@ if($$->link != T) diag(Z, "redeclare tag: %s", $2->name); $$->link = $4; - suallign($$); + sualign($$); } | LUNION sbody { @@ -1028,7 +1068,7 @@ sprint(symb, "_%d_", taggen); $$ = dotag(lookup(), TUNION, autobn); $$->link = $2; - suallign($$); + sualign($$); } | LENUM ltag { diff -r d8d00747375b sys/src/cmd/cc/com.c --- a/sys/src/cmd/cc/com.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/cc/com.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,3 +1,34 @@ +// Inferno utils/cc/com.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/com.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 #include "cc.h" int compar(Node*, int); @@ -97,7 +128,7 @@ case ORETURN: if(l == Z) { if(n->type->etype != TVOID) - warn(n, "null return of a typed function"); + diag(n, "null return of a typed function"); break; } if(tcom(l)) @@ -221,8 +252,6 @@ if(tcompat(n, l->type, r->type, tand)) goto bad; n->type = l->type; - n->right = new1(OCAST, r, Z); - n->right->type = types[TINT]; if(typeu[n->type->etype]) { if(n->op == OASASHR) n->op = OASLSHR; @@ -610,6 +639,11 @@ n->addable = 1; if(n->class == CEXREG) { n->op = OREGISTER; + // on 386 or amd64, "extern register" generates + // memory references relative to the + // gs or fs segment. + if(thechar == '8' || thechar == '6') // [sic] + n->op = OEXREG; n->reg = n->sym->offset; n->xoffset = 0; break; @@ -620,7 +654,9 @@ if(n->type->link != types[TUSHORT]) { o = outstring(0, 0); while(o & 3) { - outlstring(L"", sizeof(ushort)); + ushort a[1]; + a[0] = 0; + outlstring(a, sizeof(ushort)); o = outlstring(0, 0); } } @@ -766,7 +802,19 @@ n->type, t, l); return 1; } - switch(t->etype) { +// switch(t->etype) { +// case TCHAR: +// case TSHORT: +// t = types[TINT]; +// break; +// +// case TUCHAR: +// case TUSHORT: +// t = types[TUINT]; +// break; +// } + } else { + switch(n->type->etype) { case TCHAR: case TSHORT: t = types[TINT]; @@ -776,23 +824,12 @@ case TUSHORT: t = types[TUINT]; break; + + case TFLOAT: + t = types[TDOUBLE]; } - } else - switch(n->type->etype) - { - case TCHAR: - case TSHORT: - t = types[TINT]; - break; + } - case TUCHAR: - case TUSHORT: - t = types[TUINT]; - break; - - case TFLOAT: - t = types[TDOUBLE]; - } if(t != T && !sametype(t, n->type)) { n1 = new1(OXXX, Z, Z); *n1 = *n; @@ -809,7 +846,7 @@ tcomd(Node *n) { Type *t; - long o; + int32 o; o = 0; t = dotsearch(n->sym, n->left->type->link, n, &o); diff -r d8d00747375b sys/src/cmd/cc/com64.c --- a/sys/src/cmd/cc/com64.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/cc/com64.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,7 +1,38 @@ +// Inferno utils/cc/com64.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/com64.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 #include "cc.h" /* - * this is machine dependent, but it is totally + * this is machine depend, but it is totally * common on all of the 64-bit symulating machines. */ @@ -258,8 +289,6 @@ r->op = OFUNC; r->type = types[TLONG]; return 1; - case OCOND: - return 1; } } @@ -505,7 +534,6 @@ n->left = a; l = new(OADDR, l, Z); l->type = typ(TIND, l->left->type); - l->complex = l->left->complex; n->right = new(OLIST, l, r); n->complex = FNX; n->op = OFUNC; @@ -539,7 +567,6 @@ t = new(OADDR, l, 0); t->type = typ(TIND, l->type); - t->complex = l->complex; r = new(OLIST, t, r); n->left = nodvasop; diff -r d8d00747375b sys/src/cmd/cc/compat --- a/sys/src/cmd/cc/compat Thu Sep 29 03:00:00 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ - -int -myaccess(char *f) -{ - return access(f, AEXIST); -} - -void* -mysbrk(ulong size) -{ - return sbrk(size); -} - -int -mycreat(char *n, int p) -{ - - return create(n, 1, p); -} - -int -mywait(int *s) -{ - int p; - Waitmsg *w; - - if((w = wait()) == nil) - return -1; - else{ - p = w->pid; - *s = 0; - if(w->msg[0]) - *s = 1; - free(w); - return p; - } -} - -int -mydup(int f1, int f2) -{ - return dup(f1,f2); -} - -int -mypipe(int *fd) -{ - return pipe(fd); -} - -int -systemtype(int sys) -{ - return sys & Plan9; -} - -int -pathchar(void) -{ - return '/'; -} - -char* -mygetwd(char *path, int len) -{ - return getwd(path, len); -} - -int -myexec(char *path, char *argv[]) -{ - return exec(path, argv); -} - -int -myfork(void) -{ - return fork(); -} diff -r d8d00747375b sys/src/cmd/cc/compat.c --- a/sys/src/cmd/cc/compat.c Thu Sep 29 03:00:00 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -#include "cc.h" -#include "compat" - -/* - * fake mallocs - */ -void* -malloc(ulong n) -{ - return alloc(n); -} - -void* -calloc(ulong m, ulong n) -{ - return alloc(m*n); -} - -void* -realloc(void*, ulong) -{ - fprint(2, "realloc called\n"); - abort(); - return 0; -} - -void -free(void*) -{ -} - -/* needed when profiling */ -void* -mallocz(ulong size, int clr) -{ - void *v; - - v = alloc(size); - if(clr && v != nil) - memset(v, 0, size); - return v; -} - -void -setmalloctag(void*, ulong) -{ -} diff -r d8d00747375b sys/src/cmd/cc/dcl.c --- a/sys/src/cmd/cc/dcl.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/cc/dcl.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,3 +1,34 @@ +// Inferno utils/cc/dcl.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/dcl.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 #include "cc.h" Node* @@ -5,7 +36,7 @@ { Sym *s; Node *n1; - long v; + int32 v; nearln = lineno; lastfield = 0; @@ -100,6 +131,7 @@ if(debug['d']) dbgdecl(s); acidvar(s); + godefvar(s); s->varlineno = lineno; break; } @@ -153,7 +185,7 @@ } Node* -doinit(Sym *s, Type *t, long o, Node *a) +doinit(Sym *s, Type *t, int32 o, Node *a) { Node *n; @@ -165,7 +197,7 @@ dbgdecl(s); } if(debug['i']) { - print("t = %T; o = %ld; n = %s\n", t, o, s->name); + print("t = %T; o = %d; n = %s\n", t, o, s->name); prtree(a, "doinit value"); } @@ -282,18 +314,18 @@ } Node* -init1(Sym *s, Type *t, long o, int exflag) +init1(Sym *s, Type *t, int32 o, int exflag) { Node *a, *l, *r, nod; Type *t1; - long e, w, so, mw; + int32 e, w, so, mw; a = peekinit(); if(a == Z) return Z; if(debug['i']) { - print("t = %T; o = %ld; n = %s\n", t, o, s->name); + print("t = %T; o = %d; n = %s\n", t, o, s->name); prtree(a, "init1 value"); } @@ -449,7 +481,7 @@ e = r->vconst; if(t->width != 0) if(e < 0 || e*w >= t->width) { - diag(a, "initialization index out of range: %ld", e); + diag(a, "initialization index out of range: %d", e); continue; } } @@ -519,12 +551,13 @@ } void -suallign(Type *t) +sualign(Type *t) { Type *l; - long o, w; + int32 o, w, maxal; o = 0; + maxal = 0; switch(t->etype) { case TSTRUCT: @@ -534,28 +567,29 @@ if(l->nbits) { if(l->shift <= 0) { l->shift = -l->shift; - w = round(w, tfield->width); + w = xround(w, tfield->width); o = w; w += tfield->width; } l->offset = o; } else { - if(l->width < 0 || - l->width == 0 && l->down != T) + if(l->width <= 0) + if(l->down != T) if(l->sym) diag(Z, "incomplete structure element: %s", l->sym->name); else diag(Z, "incomplete structure element"); - w = align(w, l, Ael1); + w = align(w, l, Ael1, &maxal); l->offset = w; - w = align(w, l, Ael2); + w = align(w, l, Ael2, &maxal); } } - w = align(w, t, Asu2); + w = align(w, t, Asu2, &maxal); t->width = w; + t->align = maxal; acidtype(t); - pickletype(t); + godeftype(t); return; case TUNION: @@ -570,24 +604,25 @@ diag(Z, "incomplete union element"); l->offset = 0; l->shift = 0; - o = align(align(0, l, Ael1), l, Ael2); + o = align(align(0, l, Ael1, &maxal), l, Ael2, &maxal); if(o > w) w = o; } - w = align(w, t, Asu2); + w = align(w, t, Asu2, &maxal); t->width = w; + t->align = maxal; acidtype(t); - pickletype(t); + godeftype(t); return; default: - diag(Z, "unknown type in suallign: %T", t); + diag(Z, "unknown type in sualign: %T", t); break; } } -long -round(long v, int w) +int32 +xround(int32 v, int w) { int r; @@ -633,7 +668,7 @@ { Type *t; - autoffset = align(0, thisfn->link, Aarg0); + autoffset = align(0, thisfn->link, Aarg0, nil); stkoff = 0; for(; n->left != Z; n = n->left) { if(n->op != OFUNC || n->left->op != ONAME) @@ -715,9 +750,9 @@ firstarg = s; firstargtype = s->type; } - autoffset = align(autoffset, s->type, Aarg1); + autoffset = align(autoffset, s->type, Aarg1, nil); s->offset = autoffset; - autoffset = align(autoffset, s->type, Aarg2); + autoffset = align(autoffset, s->type, Aarg2, nil); } else dodecl(pdecl, CXXX, types[TINT], n); break; @@ -886,7 +921,7 @@ void dbgdecl(Sym *s) { - print("decl \"%s\": C=%s [B=%d:O=%ld] T=%T\n", + print("decl \"%s\": C=%s [B=%d:O=%d] T=%T\n", s->name, cnames[s->class], s->block, s->offset, s->type); } @@ -975,12 +1010,6 @@ snap(t1); if(t2->link == T) snap(t2); - if(t1 != t2 && t1->link == T && t2->link == T){ - /* structs with missing or different tag names aren't considered equal */ - if(t1->tag == nil || t2->tag == nil || - strcmp(t1->tag->name, t2->tag->name) != 0) - return 0; - } t1 = t1->link; t2 = t2->link; for(;;) { @@ -1033,12 +1062,12 @@ return -1; } -static ulong +static uint32 signat(Type *t, Typetab *tt) { int i; Type *t1; - long s; + int32 s; s = 0; for(; t; t=t->link) { @@ -1071,10 +1100,10 @@ return s; } -ulong +uint32 signature(Type *t) { - ulong s; + uint32 s; Typetab tt; tt.n = 0; @@ -1084,10 +1113,10 @@ return s; } -ulong +uint32 sign(Sym *s) { - ulong v; + uint32 v; Type *t; if(s->sig == SIGINTERN) @@ -1251,7 +1280,7 @@ } switch(c) { case CAUTO: - autoffset = align(autoffset, t, Aaut3); + autoffset = align(autoffset, t, Aaut3, nil); stkoff = maxround(stkoff, autoffset); s->offset = -autoffset; break; @@ -1261,10 +1290,10 @@ firstarg = s; firstargtype = t; } - autoffset = align(autoffset, t, Aarg1); + autoffset = align(autoffset, t, Aarg1, nil); if(s) s->offset = autoffset; - autoffset = align(autoffset, t, Aarg2); + autoffset = align(autoffset, t, Aarg2, nil); break; } } @@ -1289,7 +1318,7 @@ void xdecl(int c, Type *t, Sym *s) { - long o; + int32 o; o = 0; switch(c) { @@ -1350,7 +1379,6 @@ Type *ta, *tb, *t2; t2 = s->type; -/*print("merge %T; %T\n", t1, t2);/**/ for(;;) { if(t1 == T || t2 == T || t1 == t2) break; @@ -1511,10 +1539,11 @@ if(debug['d']) dbgdecl(s); acidvar(s); + godefvar(s); } void -symadjust(Sym *s, Node *n, long del) +symadjust(Sym *s, Node *n, int32 del) { switch(n->op) { @@ -1540,14 +1569,14 @@ } Node* -contig(Sym *s, Node *n, long v) +contig(Sym *s, Node *n, int32 v) { Node *p, *r, *q, *m; - long w; + int32 w; Type *zt; if(debug['i']) { - print("contig v = %ld; s = %s\n", v, s->name); + print("contig v = %d; s = %s\n", v, s->name); prtree(n, "doinit value"); } @@ -1563,7 +1592,7 @@ if(v != 0) diag(n, "automatic adjustable array: %s", s->name); v = s->offset; - autoffset = align(autoffset, s->type, Aaut3); + autoffset = align(autoffset, s->type, Aaut3, nil); s->offset = -autoffset; stkoff = maxround(stkoff, autoffset); symadjust(s, n, v - s->offset); diff -r d8d00747375b sys/src/cmd/cc/dpchk.c --- a/sys/src/cmd/cc/dpchk.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/cc/dpchk.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,3 +1,34 @@ +// Inferno utils/cc/dpchk.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/dpchk.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 #include "cc.h" #include "y.tab.h" @@ -26,12 +57,14 @@ { char* name; int param; + int count; Tname* link; + Tprot* prot; }; static Type* indchar; static uchar flagbits[512]; -static char fmtbuf[100]; +static char* lastfmt; static int lastadj; static int lastverb; static int nstar; @@ -67,17 +100,17 @@ { Bits flag; int f; - char *fmt; + Fmt fmt; Rune c; - fmt = fmtbuf; flag = zbits; nstar = 0; + fmtstrinit(&fmt); for(;;) { s += chartorune(&c, s); - fmt += runetochar(fmt, &c); if(c == 0 || c >= nelem(flagbits)) break; + fmtrune(&fmt, c); f = flagbits[c]; switch(f) { case Fnone: @@ -96,12 +129,13 @@ if(f >= Fverb) break; } - *fmt = 0; + free(lastfmt); + lastfmt = fmtstrflush(&fmt); return flag; } -void -newprot(Sym *m, Type *t, char *s) +static void +newprot(Sym *m, Type *t, char *s, Tprot **prot) { Bits flag; Tprot *l; @@ -111,32 +145,37 @@ return; } flag = getflag(s); - for(l=tprot; l; l=l->link) + for(l=*prot; l; l=l->link) if(beq(flag, l->flag) && sametype(t, l->type)) return; l = alloc(sizeof(*l)); l->type = t; l->flag = flag; - l->link = tprot; - tprot = l; + l->link = *prot; + *prot = l; } -void -newname(char *s, int p) +static Tname* +newname(char *s, int p, int count) { Tname *l; for(l=tname; l; l=l->link) if(strcmp(l->name, s) == 0) { - if(l->param != p) + if(p >= 0 && l->param != p) yyerror("vargck %s already defined\n", s); - return; + return l; } + if(p < 0) + return nil; + l = alloc(sizeof(*l)); l->name = s; l->param = p; l->link = tname; + l->count = count; tname = l; + return l; } void @@ -170,14 +209,40 @@ flagbits['X'] = flagbits['o']; } +static char* +getquoted(void) +{ + int c; + Rune r; + Fmt fmt; + + c = getnsc(); + if(c != '"') + return nil; + fmtstrinit(&fmt); + for(;;) { + r = getr(); + if(r == '\n') { + free(fmtstrflush(&fmt)); + return nil; + } + if(r == '"') + break; + fmtrune(&fmt, r); + } + free(lastfmt); + lastfmt = fmtstrflush(&fmt); + return strdup(lastfmt); +} + void pragvararg(void) { Sym *s; int n, c; char *t; - Rune r; Type *ty; + Tname *l; if(!debug['F']) goto out; @@ -188,6 +253,8 @@ goto cktype; if(s && strcmp(s->name, "flag") == 0) goto ckflag; + if(s && strcmp(s->name, "countpos") == 0) + goto ckcount; yyerror("syntax in #pragma varargck"); goto out; @@ -199,7 +266,18 @@ n = getnsn(); if(n < 0) goto bad; - newname(s->name, n); + newname(s->name, n, 0); + goto out; + +ckcount: +/*#pragma varargck countpos name 2*/ + s = getsym(); + if(s == S) + goto bad; + n = getnsn(); + if(n < 0) + goto bad; + newname(s->name, 0, n); goto out; ckflag: @@ -220,21 +298,29 @@ goto out; cktype: + c = getnsc(); + unget(c); + if(c != '"') { +/*#pragma varargck type name int*/ + s = getsym(); + if(s == S) + goto bad; + l = newname(s->name, -1, -1); + s = getsym(); + if(s == S) + goto bad; + ty = s->type; + while((c = getnsc()) == '*') + ty = typ(TIND, ty); + unget(c); + newprot(s, ty, "a", &l->prot); + goto out; + } + /*#pragma varargck type O int*/ - c = getnsc(); - if(c != '"') + t = getquoted(); + if(t == nil) goto bad; - t = fmtbuf; - for(;;) { - r = getr(); - if(r == ' ' || r == '\n') - goto bad; - if(r == '"') - break; - t += runetochar(t, &r); - } - *t = 0; - t = strdup(fmtbuf); s = getsym(); if(s == S) goto bad; @@ -242,7 +328,7 @@ while((c = getnsc()) == '*') ty = typ(TIND, ty); unget(c); - newprot(s, ty, t); + newprot(s, ty, t, &tprot); goto out; bad: @@ -295,7 +381,7 @@ nstar--; if(a == Z) { warn(nn, "more format than arguments %s", - fmtbuf); + lastfmt); return; } if(a->type == T) @@ -303,7 +389,7 @@ if(!sametype(types[TINT], a->type) && !sametype(types[TUINT], a->type)) warn(nn, "format mismatch '*' in %s %T, arg %d", - fmtbuf, a->type, pos); + lastfmt, a->type, pos); } for(l=tprot; l; l=l->link) if(sametype(types[TVOID], l->type)) { @@ -317,18 +403,18 @@ pos++; if(a == Z) { warn(nn, "more format than arguments %s", - fmtbuf); + lastfmt); return; } if(a->type == 0) continue; for(l=tprot; l; l=l->link) if(sametype(a->type, l->type)) { -/*print("checking %T/%ulx %T/%ulx\n", a->type, flag.b[0], l->type, l->flag.b[0]);*/ +/*print("checking %T/%ux %T/%ux\n", a->type, flag.b[0], l->type, l->flag.b[0]);*/ if(beq(flag, l->flag)) goto loop; } - warn(nn, "format mismatch %s %T, arg %d", fmtbuf, a->type, pos); + warn(nn, "format mismatch %s %T, arg %d", lastfmt, a->type, pos); loop:; } } @@ -339,7 +425,8 @@ char *s; Node *a, *b; Tname *l; - int i; + Tprot *tl; + int i, j; if(n == Z) return; @@ -353,18 +440,76 @@ if(l == 0) return; + if(l->count > 0) { + // fetch count, then check remaining length + i = l->count; + a = nil; + b = n->right; + while(i > 0) { + b = nextarg(b, &a); + i--; + } + if(a == Z) { + diag(n, "can't find count arg"); + return; + } + if(a->op != OCONST || !typechl[a->type->etype]) { + diag(n, "count is invalid constant"); + return; + } + j = a->vconst; + i = 0; + while(b != Z) { + b = nextarg(b, &a); + i++; + } + if(i != j) + diag(n, "found %d argument%s after count %d", i, i == 1 ? "" : "s", j); + } + + if(l->prot != nil) { + // check that all arguments after param or count + // are listed in type list. + i = l->count; + if(i == 0) + i = l->param; + if(i == 0) + return; + a = nil; + b = n->right; + while(i > 0) { + b = nextarg(b, &a); + i--; + } + if(a == Z) { + diag(n, "can't find count/param arg"); + return; + } + while(b != Z) { + b = nextarg(b, &a); + for(tl=l->prot; tl; tl=tl->link) + if(sametype(a->type, tl->type)) + break; + if(tl == nil) + diag(a, "invalid type %T in call to %s", a->type, s); + } + } + + if(l->param <= 0) + return; i = l->param; + a = nil; b = n->right; while(i > 0) { b = nextarg(b, &a); i--; } if(a == Z) { - warn(n, "cant find format arg"); + diag(n, "can't find format arg"); return; } if(!sametype(indchar, a->type)) { - warn(n, "format arg type %T", a->type); + diag(n, "format arg type %T", a->type); return; } if(a->op != OADDR || a->left->op != ONAME || a->left->sym != symstring) { @@ -392,9 +537,9 @@ ; if(debug['f']) if(packflg) - print("%4ld: pack %d\n", lineno, packflg); + print("%4d: pack %d\n", lineno, packflg); else - print("%4ld: pack off\n", lineno); + print("%4d: pack off\n", lineno); } void @@ -414,31 +559,25 @@ ; if(debug['f']) if(fproundflg) - print("%4ld: fproundflg %d\n", lineno, fproundflg); + print("%4d: fproundflg %d\n", lineno, fproundflg); else - print("%4ld: fproundflg off\n", lineno); + print("%4d: fproundflg off\n", lineno); } void -pragprofile(void) +pragtextflag(void) { Sym *s; - profileflg = 0; + textflag = 0; s = getsym(); - if(s) { - profileflg = atoi(s->name+1); - if(strcmp(s->name, "on") == 0 || - strcmp(s->name, "yes") == 0) - profileflg = 1; - } + textflag = 7; + if(s) + textflag = atoi(s->name+1); while(getnsc() != '\n') ; if(debug['f']) - if(profileflg) - print("%4ld: profileflg %d\n", lineno, profileflg); - else - print("%4ld: profileflg off\n", lineno); + print("%4d: textflag %d\n", lineno, textflag); } void @@ -492,3 +631,93 @@ if(debug['f']) print("%s incomplete\n", s->name); } + +Sym* +getimpsym(void) +{ + int c; + char *cp; + + c = getnsc(); + if(isspace(c) || c == '"') { + unget(c); + return S; + } + for(cp = symb;;) { + if(cp <= symb+NSYMB-4) + *cp++ = c; + c = getc(); + if(c > 0 && !isspace(c) && c != '"') + continue; + unget(c); + break; + } + *cp = 0; + if(cp > symb+NSYMB-4) + yyerror("symbol too large: %s", symb); + return lookup(); +} + +void +pragdynimport(void) +{ + Sym *local, *remote; + char *path; + Dynimp *f; + + local = getimpsym(); + if(local == nil) + goto err; + + remote = getimpsym(); + if(remote == nil) + goto err; + + path = getquoted(); + if(path == nil) + goto err; + + if(ndynimp%32 == 0) + dynimp = realloc(dynimp, (ndynimp+32)*sizeof dynimp[0]); + f = &dynimp[ndynimp++]; + f->local = local->name; + f->remote = remote->name; + f->path = path; + goto out; + +err: + yyerror("usage: #pragma dynimport local remote \"path\""); + +out: + while(getnsc() != '\n') + ; +} + +void +pragdynexport(void) +{ + Sym *local, *remote; + Dynexp *f; + + local = getsym(); + if(local == nil) + goto err; + + remote = getsym(); + if(remote == nil) + goto err; + + if(ndynexp%32 == 0) + dynexp = realloc(dynexp, (ndynexp+32)*sizeof dynexp[0]); + f = &dynexp[ndynexp++]; + f->local = local->name; + f->remote = remote->name; + goto out; + +err: + yyerror("usage: #pragma dynexport local remote"); + +out: + while(getnsc() != '\n') + ; +} diff -r d8d00747375b sys/src/cmd/cc/funct.c --- a/sys/src/cmd/cc/funct.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/cc/funct.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,3 +1,34 @@ +// Inferno utils/cc/funct.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/funct.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 #include "cc.h" typedef struct Ftab Ftab; diff -r d8d00747375b sys/src/cmd/cc/godefs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/src/cmd/cc/godefs.c Mon Nov 14 17:35:25 2011 +0100 @@ -0,0 +1,388 @@ +// cmd/cc/godefs.cc +// +// derived from pickle.cc which itself was derived from acid.cc. +// +// 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-2011 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 +#include "cc.h" + +static int upper; + +static char *kwd[] = +{ + "_bool", + "_break", + "_byte", + "_case", + "_chan", + "_complex128", + "_complex64", + "_const", + "_continue", + "_default", + "_defer", + "_else", + "_fallthrough", + "_false", + "_float32", + "_float64", + "_for", + "_func", + "_go", + "_goto", + "_if", + "_import", + "_int", + "_int16", + "_int32", + "_int64", + "_int8", + "_interface", + "_intptr", + "_map", + "_package", + "_panic", + "_range", + "_return", + "_select", + "_string", + "_struct", + "_switch", + "_true", + "_type", + "_uint", + "_uint16", + "_uint32", + "_uint64", + "_uint8", + "_uintptr", + "_var", +}; + +static char* +pmap(char *s) +{ + int i, bot, top, mid; + + bot = -1; + top = nelem(kwd); + while(top - bot > 1){ + mid = (bot + top) / 2; + i = strcmp(kwd[mid]+1, s); + if(i == 0) + return kwd[mid]; + if(i < 0) + bot = mid; + else + top = mid; + } + + return s; +} + + +int +Uconv(Fmt *fp) +{ + char str[STRINGSZ+1]; + char *s, *n; + int i; + + str[0] = 0; + s = va_arg(fp->args, char*); + + // strip package name + n = strrchr(s, '.'); + if(n != nil) + s = n + 1; + + if(s && *s) { + if(upper) + str[0] = toupper(*s); + else + str[0] = tolower(*s); + for(i = 1; i < STRINGSZ && s[i] != 0; i++) + str[i] = tolower(s[i]); + str[i] = 0; + } + + return fmtstrcpy(fp, pmap(str)); +} + + +static Sym* +findsue(Type *t) +{ + int h; + Sym *s; + + if(t != T) + for(h=0; hlink) + if(s->suetag && s->suetag->link == t) + return s; + return 0; +} + +static void +printtypename(Type *t) +{ + Sym *s; + Type *t1; + int w; + char *n; + + for( ; t != nil; t = t->link) { + switch(t->etype) { + case TIND: + // Special handling of *void. + if(t->link != nil && t->link->etype==TVOID) { + Bprint(&outbuf, "unsafe.Pointer"); + return; + } + // *func == func + if(t->link != nil && t->link->etype==TFUNC) + continue; + Bprint(&outbuf, "*"); + continue; + case TARRAY: + w = t->width; + if(t->link && t->link->width) + w /= t->link->width; + Bprint(&outbuf, "[%d]", w); + continue; + } + break; + } + + if(t == nil) { + Bprint(&outbuf, "bad // should not happen"); + return; + } + + switch(t->etype) { + case TINT: + Bprint(&outbuf, "int"); + break; + case TUINT: + Bprint(&outbuf, "uint"); + break; + case TCHAR: + Bprint(&outbuf, "int8"); + break; + case TUCHAR: + Bprint(&outbuf, "uint8"); + break; + case TSHORT: + Bprint(&outbuf, "int16"); + break; + case TUSHORT: + Bprint(&outbuf, "uint16"); + break; + case TLONG: + Bprint(&outbuf, "int32"); + break; + case TULONG: + Bprint(&outbuf, "uint32"); + break; + case TVLONG: + Bprint(&outbuf, "int64"); + break; + case TUVLONG: + Bprint(&outbuf, "uint64"); + break; + case TFLOAT: + Bprint(&outbuf, "float32"); + break; + case TDOUBLE: + Bprint(&outbuf, "float64"); + break; + case TUNION: + case TSTRUCT: + s = findsue(t->link); + n = "bad"; + if(s != S) + n = s->name; + else if(t->tag) + n = t->tag->name; + if(strcmp(n, "String") == 0){ + Bprint(&outbuf, "string"); + } else if(strcmp(n, "Slice") == 0){ + Bprint(&outbuf, "[]byte"); + } else + Bprint(&outbuf, "%U", n); + break; + case TFUNC: + Bprint(&outbuf, "func("); + for(t1 = t->down; t1 != T; t1 = t1->down) { + if(t1->etype == TVOID) + break; + if(t1 != t->down) + Bprint(&outbuf, ", "); + printtypename(t1); + } + Bprint(&outbuf, ")"); + if(t->link && t->link->etype != TVOID) { + Bprint(&outbuf, " "); + printtypename(t->link); + } + break; + case TDOT: + Bprint(&outbuf, "...interface{}"); + break; + default: + Bprint(&outbuf, " weird<%T>", t); + } +} + +static int +dontrun(void) +{ + Io *i; + int n; + + if(!debug['q'] && !debug['Q']) + return 1; + if(debug['q'] + debug['Q'] > 1) { + n = 0; + for(i=iostack; i; i=i->link) + n++; + if(n > 1) + return 1; + } + + upper = debug['Q']; + return 0; +} + +void +godeftype(Type *t) +{ + Sym *s; + Type *l; + int gotone; + + if(dontrun()) + return; + + switch(t->etype) { + case TUNION: + case TSTRUCT: + s = findsue(t->link); + if(s == S) { + Bprint(&outbuf, "/* can't find %T */\n\n", t); + return; + } + + gotone = 0; // for unions, take first member of size equal to union + Bprint(&outbuf, "type %U struct {\n", s->name); + for(l = t->link; l != T; l = l->down) { + Bprint(&outbuf, "\t"); + if(t->etype == TUNION) { + if(!gotone && l->width == t->width) + gotone = 1; + else + Bprint(&outbuf, "// (union)\t"); + } + if(l->sym != nil) // not anonymous field + Bprint(&outbuf, "%U\t", l->sym->name); + printtypename(l); + Bprint(&outbuf, "\n"); + } + Bprint(&outbuf, "}\n\n"); + break; + + default: + Bprint(&outbuf, "/* %T */\n\n", t); + break; + } +} + +void +godefvar(Sym *s) +{ + Type *t, *t1; + char n; + + if(dontrun()) + return; + + t = s->type; + if(t == nil) + return; + + switch(t->etype) { + case TENUM: + if(!typefd[t->etype]) + Bprint(&outbuf, "const %U = %lld\n", s->name, s->vconst); + else + Bprint(&outbuf, "const %U = %f\n;", s->name, s->fconst); + break; + + case TFUNC: + Bprint(&outbuf, "func %U(", s->name); + n = 'a'; + for(t1 = t->down; t1 != T; t1 = t1->down) { + if(t1->etype == TVOID) + break; + if(t1 != t->down) + Bprint(&outbuf, ", "); + Bprint(&outbuf, "%c ", n++); + printtypename(t1); + } + Bprint(&outbuf, ")"); + if(t->link && t->link->etype != TVOID) { + Bprint(&outbuf, " "); + printtypename(t->link); + } + Bprint(&outbuf, "\n"); + break; + + default: + switch(s->class) { + case CTYPEDEF: + if(!typesu[t->etype]) { + Bprint(&outbuf, "// type %U\t", s->name); + printtypename(t); + Bprint(&outbuf, "\n"); + } + break; + case CSTATIC: + case CEXTERN: + case CGLOBL: + if(strchr(s->name, '$') != nil) // TODO(lvd) + break; + Bprint(&outbuf, "var %U\t", s->name); + printtypename(t); + Bprint(&outbuf, "\n"); + break; + } + break; + } +} diff -r d8d00747375b sys/src/cmd/cc/lex.c --- a/sys/src/cmd/cc/lex.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/cc/lex.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,10 +1,57 @@ +// Inferno utils/cc/lex.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/lex.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 #include "cc.h" #include "y.tab.h" #ifndef CPP -#define CPP "/bin/cpp" +#define CPP "cpp" #endif +int +systemtype(int sys) +{ +#ifdef _WIN32 + return sys&Windows; +#else + return sys&Plan9; +#endif +} + +int +pathchar(void) +{ + return '/'; +} + /* * known debug flags * -a acid declaration output @@ -13,15 +60,20 @@ * -d print declarations * -D name define * -F format specification check + * -G print pgen stuff + * -g print cgen trees * -i print initialization * -I path include * -l generate little-endian code * -L print every NAME symbol * -M constant multiplication * -m print add/sub/mul trees - * -n print acid to file (%.c=%.acid) (with -a or -aa) + * -n print acid or godefs to file (%.c=%.acid) (with -a or -aa) * -o file output file * -p use standard cpp ANSI preprocessor (not on windows) + * -p something with peepholes + * -q print equivalent Go code for variables and types (lower-case identifiers) + * -Q print equivalent Go code for variables and types (upper-case identifiers) * -r print registerization * -s print structure offsets (with -a or -aa) * -S print assembly @@ -36,20 +88,21 @@ void main(int argc, char *argv[]) { - char *defs[50], *p; - int nproc, nout, status, i, c, ndef; + char **defs, *p; + int c, ndef; + ensuresymb(NSYMB); memset(debug, 0, sizeof(debug)); tinit(); cinit(); ginit(); arginit(); - profileflg = 1; /* #pragma can turn it off */ tufield = simplet((1L<etype) | BUNSIGNED); ndef = 0; + defs = nil; outfile = 0; - include[ninclude++] = "."; + setinclude("."); ARGBEGIN { default: c = ARGC(); @@ -73,6 +126,9 @@ case 'D': p = ARGF(); if(p) { + if(ndef%8 == 0) + defs = allocn(defs, ndef*sizeof(char *), + 8*sizeof(char *)); defs[ndef++] = p; dodefine(p); } @@ -87,56 +143,10 @@ print("usage: %cc [-options] files\n", thechar); errorexit(); } - if(argc > 1 && systemtype(Windows)){ - print("can't compile multiple files on windows\n"); + if(argc > 1){ + print("can't compile multiple files\n"); errorexit(); } - if(argc > 1 && !systemtype(Windows)) { - nproc = 1; - /* - * if we're writing acid to standard output, don't compile - * concurrently, to avoid interleaving output. - */ - if(((!debug['a'] && !debug['Z']) || debug['n']) && - (p = getenv("NPROC")) != nil) - nproc = atol(p); /* */ - c = 0; - nout = 0; - for(;;) { - while(nout < nproc && argc > 0) { - i = myfork(); - if(i < 0) { - i = mywait(&status); - if(i < 0) { - print("cannot create a process\n"); - errorexit(); - } - if(status) - c++; - nout--; - continue; - } - if(i == 0) { - fprint(2, "%s:\n", *argv); - if (compile(*argv, defs, ndef)) - errorexit(); - exits(0); - } - nout++; - argc--; - argv++; - } - i = mywait(&status); - if(i < 0) { - if(c) - errorexit(); - exits(0); - } - if(status) - c++; - nout--; - } - } if(argc == 0) c = compile("stdin", defs, ndef); @@ -151,11 +161,12 @@ int compile(char *file, char **defs, int ndef) { - char ofile[400], incfile[20]; - char *p, *av[100], opt[256]; + char *ofile, incfile[20]; + char *p, **av, opt[256]; int i, c, fd[2]; static int first = 1; + ofile = alloc(strlen(file)+10); strcpy(ofile, file); p = utfrrune(ofile, pathchar()); if(p) { @@ -174,8 +185,8 @@ p = utfrune(outfile, 0); if(debug['a'] && debug['n']) strcat(p, ".acid"); - else if(debug['Z'] && debug['n']) - strcat(p, "_pickle.c"); + else if((debug['q'] || debug['Q']) && debug['n']) + strcat(p, ".go"); else { p[0] = '.'; p[1] = thechar; @@ -200,20 +211,21 @@ * if we're writing acid to standard output, don't keep scratching * outbuf. */ - if((debug['a'] || debug['Z']) && !debug['n']) { + if((debug['a'] || debug['q'] || debug['Q']) && !debug['n']) { if (first) { outfile = 0; Binit(&outbuf, dup(1, -1), OWRITE); dup(2, 1); } } else { - c = mycreat(outfile, 0664); + c = create(outfile, OWRITE, 0664); if(c < 0) { diag(Z, "cannot open %s - %r", outfile); outfile = 0; errorexit(); } Binit(&outbuf, c, OWRITE); + outfile = strdup(outfile); } newio(); first = 0; @@ -224,22 +236,23 @@ diag(Z, "-p option not supported on windows"); errorexit(); } - if(myaccess(file) < 0) { + if(access(file, AREAD) < 0) { diag(Z, "%s does not exist", file); errorexit(); } - if(mypipe(fd) < 0) { + if(pipe(fd) < 0) { diag(Z, "pipe failed"); errorexit(); } - switch(myfork()) { + switch(fork()) { case -1: diag(Z, "fork failed"); errorexit(); case 0: close(fd[0]); - mydup(fd[1], 1); + dup(fd[1], 1); close(fd[1]); + av = alloc((ndef+ninclude+5)*sizeof(char *)); av[0] = CPP; i = 1; if(debug['.']){ @@ -250,14 +263,10 @@ sprint(opt, "-+"); av[i++] = strdup(opt); } - for(c = 0; c < ndef; c++) { - sprint(opt, "-D%s", defs[c]); - av[i++] = strdup(opt); - } - for(c = 0; c < ninclude; c++) { - sprint(opt, "-I%s", include[c]); - av[i++] = strdup(opt); - } + for(c = 0; c < ndef; c++) + av[i++] = smprint("-D%s", defs[c]); + for(c = 0; c < ninclude; c++) + av[i++] = smprint("-I%s", include[c]); if(strcmp(file, "stdin") != 0) av[i++] = file; av[i] = 0; @@ -266,7 +275,7 @@ fprint(2, "%s ", av[c]); fprint(2, "\n"); } - myexec(av[0], av); + exec(av[0], av); fprint(2, "can't exec C preprocessor %s: %r\n", CPP); errorexit(); default: @@ -281,7 +290,7 @@ newfile(file, -1); } yyparse(); - if(!debug['a'] && !debug['Z']) + if(!debug['a'] && !debug['q'] && !debug['Q']) gclean(); return nerrors; } @@ -354,7 +363,7 @@ Sym* slookup(char *s) { - + ensuresymb(strlen(s)); strcpy(symb, s); return lookup(); } @@ -363,9 +372,29 @@ lookup(void) { Sym *s; - ulong h; + uint32 h; char *p; int c, n; + char *r, *w; + + if((uchar)symb[0] == 0xc2 && (uchar)symb[1] == 0xb7) { + // turn leading · into ""· + h = strlen(symb); + ensuresymb(h+2); + memmove(symb+2, symb, h+1); + symb[0] = '"'; + symb[1] = '"'; + } + + // turn · into . + for(r=w=symb; *r; r++) { + if((uchar)*r == 0xc2 && (uchar)*(r+1) == 0xb7) { + *w++ = '.'; + r++; + }else + *w++ = *r; + } + *w = '\0'; h = 0; for(p=symb; *p;) { @@ -373,8 +402,7 @@ h += *p++; } n = (p - symb) + 1; - if((long)h < 0) - h = ~h; + h &= 0xffffff; h %= NHASH; c = symb[0]; for(s = hash[h]; s != S; s = s->link) { @@ -386,8 +414,6 @@ s = alloc(sizeof(*s)); s->name = alloc(n); memmove(s->name, symb, n); - - strcpy(s->name, symb); s->link = hash[h]; hash[h] = s; syminit(s); @@ -422,11 +448,11 @@ Numflt = 1<<4, }; -long +int32 yylex(void) { vlong vv; - long c, c1, t; + int32 c, c1, t; char *cp; Rune rune; Sym *s; @@ -569,7 +595,7 @@ vv = c; yylval.vval = convvtox(vv, TUCHAR); if(yylval.vval != vv) - yyerror("overflow in character constant: 0x%lx", c); + yyerror("overflow in character constant: 0x%x", c); else if(c & 0x80){ nearln = lineno; @@ -988,7 +1014,7 @@ return c; } -long +int32 getr(void) { int c, i; @@ -1048,10 +1074,10 @@ lineno--; } -long -escchar(long e, int longflg, int escflg) +int32 +escchar(int32 e, int longflg, int escflg) { - long c, l; + int32 c, l; int i; loop: @@ -1236,9 +1262,9 @@ dclstack = D; pathname = allocn(pathname, 0, 100); - if(mygetwd(pathname, 99) == 0) { + if(getwd(pathname, 99) == 0) { pathname = allocn(pathname, 100, 900); - if(mygetwd(pathname, 999) == 0) + if(getwd(pathname, 999) == 0) strcpy(pathname, "/???"); } @@ -1248,6 +1274,7 @@ fmtinstall('L', Lconv); fmtinstall('Q', Qconv); fmtinstall('|', VBconv); + fmtinstall('U', Uconv); } int @@ -1304,14 +1331,14 @@ struct { Hist* incl; /* start of this include file */ - long idel; /* delta line number to apply to include */ + int32 idel; /* delta line number to apply to include */ Hist* line; /* start of this #line directive */ - long ldel; /* delta line number to apply to #line */ + int32 ldel; /* delta line number to apply to #line */ } a[HISTSZ]; - long l, d; + int32 l, d; int i, n; - l = va_arg(fp->args, long); + l = va_arg(fp->args, int32); n = 0; for(h = hist; h != H; h = h->link) { if(l < h->line) @@ -1349,11 +1376,11 @@ strcat(str, " "); } if(a[i].line) - snprint(s, STRINGSZ, "%s:%ld[%s:%ld]", + snprint(s, STRINGSZ, "%s:%d[%s:%d]", a[i].line->name, l-a[i].ldel+1, a[i].incl->name, l-a[i].idel+1); else - snprint(s, STRINGSZ, "%s:%ld", + snprint(s, STRINGSZ, "%s:%d", a[i].incl->name, l-a[i].idel+1); if(strlen(s)+strlen(str) >= STRINGSZ-10) break; @@ -1371,7 +1398,7 @@ char str[STRINGSZ+20], s[STRINGSZ+20]; Type *t, *t1; int et; - long n; + int32 n; str[0] = 0; for(t = va_arg(fp->args, Type*); t != T; t = t->link) { @@ -1402,7 +1429,7 @@ n = t->width; if(t->link && t->link->width) n /= t->link->width; - sprint(s, "[%ld]", n); + sprint(s, "[%d]", n); if(strlen(str) + strlen(s) < STRINGSZ) strcat(str, s); } @@ -1441,11 +1468,11 @@ Qconv(Fmt *fp) { char str[STRINGSZ+20], *s; - long b; + int32 b; int i; str[0] = 0; - for(b = va_arg(fp->args, long); b;) { + for(b = va_arg(fp->args, int32); b;) { i = bitno(b); if(str[0]) strcat(str, " "); @@ -1482,70 +1509,62 @@ return fmtstrcpy(fp, str); } -/* - * real allocs - */ +void +setinclude(char *p) +{ + int i; + + if(*p != 0) { + for(i=1; i < ninclude; i++) + if(strcmp(p, include[i]) == 0) + return; + + if(ninclude%8 == 0) + include = allocn(include, ninclude*sizeof(char *), + 8*sizeof(char *)); + include[ninclude++] = p; + } +} + void* -alloc(long n) +alloc(int32 n) { void *p; - while((uintptr)hunk & MAXALIGN) { - hunk++; - nhunk--; + p = malloc(n); + if(p == nil) { + print("alloc out of mem\n"); + exits("alloc: out of mem"); } - while(nhunk < n) - gethunk(); - p = hunk; - nhunk -= n; - hunk += n; + memset(p, 0, n); return p; } void* -allocn(void *p, long on, long n) +allocn(void *p, int32 n, int32 d) { - void *q; - - q = (uchar*)p + on; - if(q != hunk || nhunk < n) { - while(nhunk < on+n) - gethunk(); - memmove(hunk, p, on); - p = hunk; - hunk += on; - nhunk -= on; + if(p == nil) + return alloc(n+d); + p = realloc(p, n+d); + if(p == nil) { + print("allocn out of mem\n"); + exits("allocn: out of mem"); } - hunk += n; - nhunk -= n; + if(d > 0) + memset((char*)p+n, 0, d); return p; } void -setinclude(char *p) +ensuresymb(int32 n) { - int i; - char *e; + if(symb == nil) { + symb = alloc(NSYMB+1); + nsymb = NSYMB; + } - while(*p != 0) { - e = strchr(p, ' '); - if(e != 0) - *e = '\0'; - - for(i=1; i < ninclude; i++) - if(strcmp(p, include[i]) == 0) - break; - - if(i >= ninclude) - include[ninclude++] = p; - - if(ninclude > nelem(include)) { - diag(Z, "ninclude too small %d", nelem(include)); - exits("ninclude"); - } - - if(e == 0) - break; - p = e+1; + if(n > nsymb) { + symb = allocn(symb, nsymb, n+1-nsymb); + nsymb = n; } } diff -r d8d00747375b sys/src/cmd/cc/lexbody --- a/sys/src/cmd/cc/lexbody Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/cc/lexbody Mon Nov 14 17:35:25 2011 +0100 @@ -1,3 +1,33 @@ +// Inferno utils/cc/lexbody +// http://code.google.com/p/inferno-os/source/browse/utils/cc/lexbody +// +// 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. + /* * common code for all the assemblers */ @@ -17,6 +47,20 @@ } void +pragdynimport(void) +{ + while(getnsc() != '\n') + ; +} + +void +pragdynexport(void) +{ + while(getnsc() != '\n') + ; +} + +void pragfpround(void) { while(getnsc() != '\n') @@ -24,6 +68,13 @@ } void +pragtextflag(void) +{ + while(getnsc() != '\n') + ; +} + +void pragprofile(void) { while(getnsc() != '\n') @@ -37,43 +88,47 @@ ; } -/* - * real allocs - */ void* -alloc(long n) +alloc(int32 n) { void *p; - while((uintptr)hunk & MAXALIGN) { - hunk++; - nhunk--; + p = malloc(n); + if(p == nil) { + print("alloc out of mem\n"); + exits("alloc: out of mem"); } - while(nhunk < n) - gethunk(); - p = hunk; - nhunk -= n; - hunk += n; + memset(p, 0, n); return p; } void* -allocn(void *p, long on, long n) +allocn(void *p, int32 n, int32 d) { - void *q; + if(p == nil) + return alloc(n+d); + p = realloc(p, n+d); + if(p == nil) { + print("allocn out of mem\n"); + exits("allocn: out of mem"); + } + if(d > 0) + memset((char*)p+n, 0, d); + return p; +} - q = (uchar*)p + on; - if(q != hunk || nhunk < n) { - while(nhunk < on+n) - gethunk(); - memmove(hunk, p, on); - p = hunk; - hunk += on; - nhunk -= on; +void +ensuresymb(int32 n) +{ + if(symb == nil) { + symb = alloc(NSYMB+1); + nsymb = NSYMB; } - hunk += n; - nhunk -= n; - return p; + + if(n > nsymb) { + symb = allocn(symb, nsymb, n+1-nsymb); + nsymb = n; + } } void @@ -86,11 +141,10 @@ for(i=1; i < ninclude; i++) if(strcmp(p, include[i]) == 0) return; - - if(ninclude >= nelem(include)) { - yyerror("ninclude too small %d", nelem(include)); - exits("ninclude"); - } + + if(ninclude%8 == 0) + include = allocn(include, ninclude*sizeof(char *), + 8*sizeof(char *)); include[ninclude++] = p; } @@ -160,7 +214,7 @@ Sym* slookup(char *s) { - + ensuresymb(strlen(s)); strcpy(symb, s); return lookup(); } @@ -169,16 +223,35 @@ lookup(void) { Sym *s; - long h; + int32 h; char *p; int c, l; + char *r, *w; + + if((uchar)symb[0] == 0xc2 && (uchar)symb[1] == 0xb7) { + // turn leading · into ""· + h = strlen(symb); + ensuresymb(h+2); + memmove(symb+2, symb, h+1); + symb[0] = '"'; + symb[1] = '"'; + } + + // turn · into . + for(r=w=symb; *r; r++) { + if((uchar)*r == 0xc2 && (uchar)*(r+1) == 0xb7) { + *w++ = '.'; + r++; + }else + *w++ = *r; + } + *w = '\0'; h = 0; for(p=symb; c = *p; p++) h = h+h+h + c; l = (p - symb) + 1; - if(h < 0) - h = ~h; + h &= 0xffffff; h %= NHASH; c = symb[0]; for(s = hash[h]; s != S; s = s->link) { @@ -197,7 +270,17 @@ return s; } -long +int +ISALPHA(int c) +{ + if(isalpha(c)) + return 1; + if(c >= Runeself) + return 1; + return 0; +} + +int32 yylex(void) { int c, c1; @@ -224,7 +307,7 @@ } goto l0; } - if(isalpha(c)) + if(ISALPHA(c)) goto talph; if(isdigit(c)) goto tnum; @@ -240,7 +323,7 @@ case '.': c = GETC(); - if(isalpha(c)) { + if(ISALPHA(c)) { cp = symb; *cp++ = '.'; goto aloop; @@ -261,7 +344,7 @@ aloop: *cp++ = c; c = GETC(); - if(isalpha(c) || isdigit(c) || c == '_' || c == '$') + if(ISALPHA(c) || isdigit(c) || c == '_' || c == '$') goto aloop; *cp = 0; peekc = c; @@ -618,11 +701,11 @@ } void -prfile(long l) +prfile(int32 l) { int i, n; Hist a[HISTSZ], *h; - long d; + int32 d; n = 0; for(h = hist; h != H; h = h->link) { @@ -682,5 +765,5 @@ fr = modf(fr*f, &ho); ieee->l = ho; ieee->l <<= 16; - ieee->l |= (long)(fr*f); + ieee->l |= (int32)(fr*f); } diff -r d8d00747375b sys/src/cmd/cc/mac.c --- a/sys/src/cmd/cc/mac.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/cc/mac.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,3 +1,34 @@ +// Inferno utils/cc/mac.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/mac.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 #include "cc.h" #include "macbody" diff -r d8d00747375b sys/src/cmd/cc/macbody --- a/sys/src/cmd/cc/macbody Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/cc/macbody Mon Nov 14 17:35:25 2011 +0100 @@ -1,9 +1,39 @@ +// Inferno utils/cc/macbody +// http://code.google.com/p/inferno-os/source/browse/utils/cc/macbody +// +// 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. + #define VARMAC 0x80 -long +int32 getnsn(void) { - long n; + int32 n; int c; c = getnsc(); @@ -25,7 +55,7 @@ char *cp; c = getnsc(); - if(!isalpha(c) && c != '_') { + if(!isalpha(c) && c != '_' && c < 0x80) { unget(c); return S; } @@ -33,7 +63,7 @@ if(cp <= symb+NSYMB-4) *cp++ = c; c = getc(); - if(isalnum(c) || c == '_') + if(isalnum(c) || c == '_' || c >= 0x80) continue; unget(c); break; @@ -108,23 +138,17 @@ { Sym *s; char *p; - long l; + int32 l; + ensuresymb(strlen(cp)); strcpy(symb, cp); p = strchr(symb, '='); if(p) { *p++ = 0; s = lookup(); l = strlen(p) + 2; /* +1 null, +1 nargs */ - while(l & 3) - l++; - while(nhunk < l) - gethunk(); - *hunk = 0; - strcpy(hunk+1, p); - s->macro = hunk; - hunk += l; - nhunk -= l; + s->macro = alloc(l); + strcpy(s->macro+1, p); } else { s = lookup(); s->macro = "\0001"; /* \000 is nargs */ @@ -260,7 +284,7 @@ continue; } if(ischr){ - if(c == '\\'){ + if(c == '\\'){ base = allocn(base, len, 1); base[len++] = c; c = getc(); @@ -377,7 +401,7 @@ print("#expand %s %s\n", s->name, ob); return; } - + nargs = (char)(*s->macro & ~VARMAC) - 1; dots = *s->macro & VARMAC; @@ -551,26 +575,21 @@ for(i=0; i') continue; + ensuresymb(strlen(include[i])+strlen(str)+2); strcpy(symb, include[i]); strcat(symb, "/"); if(strcmp(symb, "./") == 0) symb[0] = 0; strcat(symb, str); - f = open(symb, 0); + f = open(symb, OREAD); if(f >= 0) break; } if(f < 0) strcpy(symb, str); c = strlen(symb) + 1; - while(c & 3) - c++; - while(nhunk < c) - gethunk(); - hp = hunk; - memcpy(hunk, symb, c); - nhunk -= c; - hunk += c; + hp = alloc(c); + memcpy(hp, symb, c); newio(); pushio(); newfile(hp, f); @@ -587,7 +606,7 @@ { char *cp; int c; - long n; + int32 n; n = getnsn(); c = getc(); @@ -621,14 +640,8 @@ nn: c = strlen(symb) + 1; - while(c & 3) - c++; - while(nhunk < c) - gethunk(); - cp = hunk; - memcpy(hunk, symb, c); - nhunk -= c; - hunk += c; + cp = alloc(c); + memcpy(cp, symb, c); linehist(cp, n); return; @@ -714,8 +727,8 @@ pragfpround(); return; } - if(s && strcmp(s->name, "profile") == 0) { - pragprofile(); + if(s && strcmp(s->name, "textflag") == 0) { + pragtextflag(); return; } if(s && strcmp(s->name, "varargck") == 0) { @@ -726,6 +739,14 @@ pragincomplete(); return; } + if(s && strcmp(s->name, "dynimport") == 0) { + pragdynimport(); + return; + } + if(s && strcmp(s->name, "dynexport") == 0) { + pragdynexport(); + return; + } while(getnsc() != '\n') ; return; @@ -752,17 +773,11 @@ goto bad; /* - * put pragma-line in as a funny history + * put pragma-line in as a funny history */ c = strlen(symb) + 1; - while(c & 3) - c++; - while(nhunk < c) - gethunk(); - hp = hunk; - memcpy(hunk, symb, c); - nhunk -= c; - hunk += c; + hp = alloc(c); + memcpy(hp, symb, c); h = alloc(sizeof(Hist)); h->name = hp; @@ -815,11 +830,11 @@ if(debug['f']) if(f) { if(offset) - print("%4ld: %s (#line %d)\n", lineno, f, offset); + print("%4d: %s (#line %d)\n", lineno, f, offset); else - print("%4ld: %s\n", lineno, f); + print("%4d: %s\n", lineno, f); } else - print("%4ld: \n", lineno); + print("%4d: \n", lineno); newflag = 0; h = alloc(sizeof(Hist)); @@ -835,22 +850,3 @@ ehist->link = h; ehist = h; } - -void -gethunk(void) -{ - char *h; - long nh; - - nh = NHUNK; - if(thunk >= 10L*NHUNK) - nh = 10L*NHUNK; - h = (char*)mysbrk(nh); - if(h == (char*)-1) { - yyerror("out of memory"); - errorexit(); - } - hunk = h; - nhunk = nh; - thunk += nh; -} diff -r d8d00747375b sys/src/cmd/cc/mkfile --- a/sys/src/cmd/cc/mkfile Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/cc/mkfile Mon Nov 14 17:35:25 2011 +0100 @@ -7,16 +7,15 @@ mac.$O\ dcl.$O\ acid.$O\ - pickle.$O\ bits.$O\ com.$O\ scon.$O\ funct.$O\ sub.$O\ com64.$O\ - compat.$O\ dpchk.$O\ omachcap.$O\ + godefs.$O\ HFILES=cc.h\ y.tab.h\ diff -r d8d00747375b sys/src/cmd/cc/omachcap.c --- a/sys/src/cmd/cc/omachcap.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/cc/omachcap.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,8 +1,40 @@ +// Inferno utils/cc/machcap.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/machcap.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 #include "cc.h" /* default, like old cc */ int -machcap(Node*) +machcap(Node *n) { + USED(n); return 0; } diff -r d8d00747375b sys/src/cmd/cc/pgen.c --- a/sys/src/cmd/cc/pgen.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/cc/pgen.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,5 +1,65 @@ +// Inferno utils/6c/sgen.c +// http://code.google.com/p/inferno-os/source/browse/utils/6c/sgen.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 "gc.h" +vlong +argsize(void) +{ + Type *t; + int32 s; + +//print("t=%T\n", thisfn); + s = align(0, thisfn->link, Aarg0, nil); + for(t=thisfn->down; t!=T; t=t->down) { + switch(t->etype) { + case TVOID: + break; + case TDOT: + yyerror("function takes ... without textflag NOSPLIT"); + s += 64; + break; + default: + s = align(s, t, Aarg1, nil); + s = align(s, t, Aarg2, nil); + break; + } +//print(" %d %T\n", s, t); + } + if(thechar == '6') + s = (s+7) & ~7; + else + s = (s+3) & ~3; + return s; +} + void codgen(Node *n, Node *nn) { @@ -9,7 +69,6 @@ cursafe = 0; curarg = 0; maxargsafe = 0; - hasdoubled = 0; /* * isolate name @@ -23,63 +82,45 @@ break; } nearln = nn->lineno; - gpseudo(ATEXT, n1->sym, nodconst(stkoff)); + + p = gtext(n1->sym, stkoff); sp = p; - if(typecmplx[thisfn->link->etype]) { - if(nodret == nil) { - nodret = new(ONAME, Z, Z); - nodret->sym = slookup(".ret"); - nodret->class = CPARAM; - nodret->type = types[TIND]; - nodret->etype = TIND; - nodret = new(OIND, nodret, Z); - } - n1 = nodret->left; - if(n1->type == T || n1->type->link != thisfn->link) { - n1->type = typ(TIND, thisfn->link); - n1->etype = n1->type->etype; - nodret = new(OIND, n1, Z); - complex(nodret); - } - } - /* * isolate first argument */ - if(REGARG >= 0) { - if(typecmplx[thisfn->link->etype]) { + if(REGARG >= 0) { + if(typesuv[thisfn->link->etype]) { nod1 = *nodret->left; nodreg(&nod, &nod1, REGARG); gmove(&nod, &nod1); } else - if(firstarg && typeword[firstargtype->etype]) { - nod1 = znode; - nod1.op = ONAME; + if(firstarg && typechlp[firstargtype->etype]) { + nod1 = *nodret->left; nod1.sym = firstarg; nod1.type = firstargtype; - nod1.class = CPARAM; - nod1.xoffset = align(0, firstargtype, Aarg1); + nod1.xoffset = align(0, firstargtype, Aarg1, nil); nod1.etype = firstargtype->etype; - xcom(&nod1); nodreg(&nod, &nod1, REGARG); gmove(&nod, &nod1); } } + retok = 0; + canreach = 1; warnreach = 1; gen(n); if(canreach && thisfn->link->etype != TVOID) - warn(Z, "no return at end of function: %s", n1->sym->name); + diag(Z, "no return at end of function: %s", n1->sym->name); noretval(3); gbranch(ORETURN); if(!debug['N'] || debug['R'] || debug['P']) regopt(sp); - - if(thechar=='6' || thechar=='7' || thechar=='9' || hasdoubled) /* [sic] */ - maxargsafe = round(maxargsafe, 8); + + if(thechar=='6' || thechar=='7') /* [sic] */ + maxargsafe = xround(maxargsafe, 8); sp->to.offset += maxargsafe; } @@ -170,13 +211,7 @@ break; } if(typecmplx[n->type->etype]) { - nod = znode; - nod.op = OAS; - nod.left = nodret; - nod.right = l; - nod.type = n->type; - nod.complex = l->complex; - cgen(&nod, Z); + sugen(l, nodret, n->type->width); noretval(3); gbranch(ORETURN); break; @@ -231,7 +266,7 @@ if(cases == C) diag(n, "case/default outside a switch"); if(l == Z) { - casf(); + newcase(); cases->val = 0; cases->def = 1; cases->label = pc; @@ -243,7 +278,7 @@ goto rloop; if(l->op == OCONST) if(typeword[l->type->etype] && l->type->etype != TIND) { - casf(); + newcase(); cases->val = l->vconst; cases->def = 0; cases->label = pc; @@ -268,7 +303,7 @@ cn = cases; cases = C; - casf(); + newcase(); sbc = breakpc; breakpc = pc; @@ -355,8 +390,8 @@ gbranch(OGOTO); /* entry */ sp = p; - /* - * if there are no incoming labels in the + /* + * if there are no incoming labels in the * body and the top's not reachable, warn */ if(!canreach && warnreach && deadheads(n)) { @@ -380,7 +415,7 @@ patch(spc, pc); gen(l->right->right); /* inc */ - patch(sp, pc); + patch(sp, pc); if(l->left != Z) { /* test */ bcomplex(l->left, Z); patch(p, breakpc); @@ -430,7 +465,7 @@ * Don't complain about unreachable break statements. * There are breaks hidden in yacc's output and some people * write return; break; in their switch statements out of habit. - * However, don't confuse the analysis by inserting an + * However, don't confuse the analysis by inserting an * unreachable reference to breakpc either. */ if(!canreach) @@ -458,7 +493,7 @@ canreach = 1; gen(n->right->right); /* - * treat constant ifs as regular ifs for + * treat constant ifs as regular ifs for * reachability warnings. */ if(!canreach && oldreach && debug['w'] < 2) @@ -471,7 +506,7 @@ canreach = 1; supgen(n->right->right); /* - * treat constant ifs as regular ifs for + * treat constant ifs as regular ifs for * reachability warnings. */ if(!oldreach && canreach && debug['w'] < 2) @@ -531,6 +566,7 @@ int bcomplex(Node *n, Node *c) { + Node *b, nod; complex(n); if(n->type != T) @@ -542,6 +578,16 @@ } if(c != Z && n->op == OCONST && deadheads(c)) return 1; + if(typev[n->type->etype] && machcap(Z)) { + b = &nod; + b->op = ONE; + b->left = n; + b->right = new(0, Z, Z); + *b->right = *nodconst(0); + b->right->type = n->type; + b->type = types[TLONG]; + n = b; + } bool64(n); boolgen(n, 1, Z); return 0; diff -r d8d00747375b sys/src/cmd/cc/pickle.c --- a/sys/src/cmd/cc/pickle.c Thu Sep 29 03:00:00 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,268 +0,0 @@ -#include "cc.h" - -static char *kwd[] = -{ - "$adt", "$aggr", "$append", "$complex", "$defn", - "$delete", "$do", "$else", "$eval", "$head", "$if", - "$local", "$loop", "$return", "$tail", "$then", - "$union", "$whatis", "$while", -}; -static char picklestr[] = "\tbp = pickle(bp, ep, un, "; - -static char* -pmap(char *s) -{ - int i, bot, top, new; - - bot = 0; - top = bot + nelem(kwd) - 1; - while(bot <= top){ - new = bot + (top - bot)/2; - i = strcmp(kwd[new]+1, s); - if(i == 0) - return kwd[new]; - - if(i < 0) - bot = new + 1; - else - top = new - 1; - } - return s; -} - -Sym* -picklesue(Type *t) -{ - int h; - Sym *s; - - if(t != T) - for(h=0; hlink) - if(s->suetag && s->suetag->link == t) - return s; - return 0; -} - -Sym* -picklefun(Type *t) -{ - int h; - Sym *s; - - for(h=0; hlink) - if(s->type == t) - return s; - return 0; -} - -char picklechar[NTYPE]; -Init picklecinit[] = -{ - TCHAR, 'C', 0, - TUCHAR, 'b', 0, - TSHORT, 'd', 0, - TUSHORT, 'u', 0, - TLONG, 'D', 0, - TULONG, 'U', 0, - TVLONG, 'V', 0, - TUVLONG, 'W', 0, - TFLOAT, 'f', 0, - TDOUBLE, 'F', 0, - TARRAY, 'a', 0, - TIND, 'X', 0, - -1, 0, 0, -}; - -static void -pickleinit(void) -{ - Init *p; - - for(p=picklecinit; p->code >= 0; p++) - picklechar[p->code] = p->value; - - picklechar[TINT] = picklechar[TLONG]; - picklechar[TUINT] = picklechar[TULONG]; - if(types[TINT]->width != types[TLONG]->width) { - picklechar[TINT] = picklechar[TSHORT]; - picklechar[TUINT] = picklechar[TUSHORT]; - if(types[TINT]->width != types[TSHORT]->width) - warn(Z, "picklemember int not long or short"); - } - -} - -void -picklemember(Type *t, long off) -{ - Sym *s, *s1; - static int picklecharinit = 0; - - if(picklecharinit == 0) { - pickleinit(); - picklecharinit = 1; - } - s = t->sym; - switch(t->etype) { - default: - Bprint(&outbuf, " T%d\n", t->etype); - break; - - case TIND: - if(s == S) - Bprint(&outbuf, - "%s\"p\", (char*)addr+%ld+_i*%ld);\n", - picklestr, t->offset+off, t->width); - else - Bprint(&outbuf, - "%s\"p\", &addr->%s);\n", - picklestr, pmap(s->name)); - break; - - case TINT: - case TUINT: - case TCHAR: - case TUCHAR: - case TSHORT: - case TUSHORT: - case TLONG: - case TULONG: - case TVLONG: - case TUVLONG: - case TFLOAT: - case TDOUBLE: - if(s == S) - Bprint(&outbuf, "%s\"%c\", (char*)addr+%ld+_i*%ld);\n", - picklestr, picklechar[t->etype], t->offset+off, t->width); - else - Bprint(&outbuf, "%s\"%c\", &addr->%s);\n", - picklestr, picklechar[t->etype], pmap(s->name)); - break; - case TARRAY: - Bprint(&outbuf, "\tfor(_i = 0; _i < %ld; _i++) {\n\t", - t->width/t->link->width); - picklemember(t->link, t->offset+off); - Bprint(&outbuf, "\t}\n\t_i = 0;\n\tUSED(_i);\n"); - break; - - case TSTRUCT: - case TUNION: - s1 = picklesue(t->link); - if(s1 == S) - break; - if(s == S) { - Bprint(&outbuf, "\tbp = pickle_%s(bp, ep, un, (%s*)((char*)addr+%ld+_i*%ld));\n", - pmap(s1->name), pmap(s1->name), t->offset+off, t->width); - } else { - Bprint(&outbuf, "\tbp = pickle_%s(bp, ep, un, &addr->%s);\n", - pmap(s1->name), pmap(s->name)); - } - break; - } -} - -void -pickletype(Type *t) -{ - Sym *s; - Type *l; - Io *i; - int n; - char *an; - - if(!debug['P']) - return; - if(debug['P'] > 1) { - n = 0; - for(i=iostack; i; i=i->link) - n++; - if(n > 1) - return; - } - s = picklesue(t->link); - if(s == S) - return; - switch(t->etype) { - default: - Bprint(&outbuf, "T%d\n", t->etype); - return; - - case TUNION: - case TSTRUCT: - if(debug['s']) - goto asmstr; - an = pmap(s->name); - - Bprint(&outbuf, "uchar*\npickle_%s(uchar *bp, uchar *ep, int un, %s *addr)\n{\n\tint _i = 0;\n\n\tUSED(_i);\n", an, an); - for(l = t->link; l != T; l = l->down) - picklemember(l, 0); - Bprint(&outbuf, "\treturn bp;\n}\n\n"); - break; - asmstr: - if(s == S) - break; - for(l = t->link; l != T; l = l->down) - if(l->sym != S) - Bprint(&outbuf, "#define\t%s.%s\t%ld\n", - s->name, - l->sym->name, - l->offset); - break; - } -} - -void -picklevar(Sym *s) -{ - int n; - Io *i; - Type *t; - Sym *s1, *s2; - - if(!debug['P'] || debug['s']) - return; - if(debug['P'] > 1) { - n = 0; - for(i=iostack; i; i=i->link) - n++; - if(n > 1) - return; - } - t = s->type; - while(t && t->etype == TIND) - t = t->link; - if(t == T) - return; - if(t->etype == TENUM) { - Bprint(&outbuf, "%s = ", pmap(s->name)); - if(!typefd[t->etype]) - Bprint(&outbuf, "%lld;\n", s->vconst); - else - Bprint(&outbuf, "%f\n;", s->fconst); - return; - } - if(!typesu[t->etype]) - return; - s1 = picklesue(t->link); - if(s1 == S) - return; - switch(s->class) { - case CAUTO: - case CPARAM: - s2 = picklefun(thisfn); - if(s2) - Bprint(&outbuf, "complex %s %s:%s;\n", - pmap(s1->name), pmap(s2->name), pmap(s->name)); - break; - - case CSTATIC: - case CEXTERN: - case CGLOBL: - case CLOCAL: - Bprint(&outbuf, "complex %s %s;\n", - pmap(s1->name), pmap(s->name)); - break; - } -} diff -r d8d00747375b sys/src/cmd/cc/pswt.c --- a/sys/src/cmd/cc/pswt.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/cc/pswt.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,3 +1,33 @@ +// Inferno utils/6c/swt.c +// http://code.google.com/p/inferno-os/source/browse/utils/6c/swt.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 "gc.h" int @@ -17,8 +47,7 @@ { Case *c; C1 *q, *iq; - long def, nc, i, isv; - int dup; + int32 def, nc, i, isv; def = 0; nc = 0; @@ -45,21 +74,16 @@ if(isv) q->val = c->val; else - q->val = (long)c->val; /* cast ensures correct value for 32-bit switch on 64-bit architecture */ + q->val = (int32)c->val; /* cast ensures correct value for 32-bit switch on 64-bit architecture */ q++; } qsort(iq, nc, sizeof(C1), swcmp); if(debug['W']) for(i=0; i 0) { c = *s++; - if(align(0, types[TCHAR], Aarg1)) { + if(align(0, types[TCHAR], Aarg1, nil)) { buf[0] = c>>8; buf[1] = c; } else { @@ -140,5 +164,5 @@ fr = modf(fr*f, &ho); ieee->l = ho; ieee->l <<= 16; - ieee->l |= (long)(fr*f); + ieee->l |= (int32)(fr*f); } diff -r d8d00747375b sys/src/cmd/cc/scon.c --- a/sys/src/cmd/cc/scon.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/cc/scon.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,3 +1,34 @@ +// Inferno utils/cc/scon.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/scon.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 #include "cc.h" static Node* diff -r d8d00747375b sys/src/cmd/cc/sub.c --- a/sys/src/cmd/cc/sub.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/cmd/cc/sub.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,3 +1,34 @@ +// Inferno utils/cc/sub.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/sub.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 #include "cc.h" Node* @@ -62,18 +93,18 @@ { case ONAME: print(" \"%F\"", n); - print(" %ld", n->xoffset); + print(" %d", n->xoffset); i = 0; break; case OINDREG: - print(" %ld(R%d)", n->xoffset, n->reg); + print(" %d(R%d)", n->xoffset, n->reg); i = 0; break; case OREGISTER: if(n->xoffset) - print(" %ld+R%d", n->xoffset, n->reg); + print(" %d+R%d", n->xoffset, n->reg); else print(" R%d", n->reg); i = 0; @@ -144,7 +175,7 @@ } Type* -garbt(Type *t, long b) +garbt(Type *t, int32 b) { Type *t1; @@ -157,7 +188,7 @@ } int -simpleg(long b) +simpleg(int32 b) { b &= BGARB; @@ -173,7 +204,7 @@ } int -simplec(long b) +simplec(int32 b) { b &= BCLASS; @@ -200,7 +231,7 @@ } Type* -simplet(long b) +simplet(int32 b) { b &= ~BCLASS & ~BGARB; @@ -269,10 +300,10 @@ } int -stcompat(Node *n, Type *t1, Type *t2, long ttab[]) +stcompat(Node *n, Type *t1, Type *t2, int32 ttab[]) { int i; - ulong b; + uint32 b; i = 0; if(t2 != T) @@ -296,7 +327,7 @@ } int -tcompat(Node *n, Type *t1, Type *t2, long ttab[]) +tcompat(Node *n, Type *t1, Type *t2, int32 ttab[]) { if(stcompat(n, t1, t2, ttab)) { @@ -312,7 +343,7 @@ } void -makedot(Node *n, Type *t, long o) +makedot(Node *n, Type *t, int32 o) { Node *n1, *n2; @@ -359,7 +390,7 @@ } Type* -dotsearch(Sym *s, Type *t, Node *n, long *off) +dotsearch(Sym *s, Type *t, Node *n, int32 *off) { Type *t1, *xt, *rt; @@ -411,12 +442,12 @@ return xt; } -long +int32 dotoffset(Type *st, Type *lt, Node *n) { Type *t; Sym *g; - long o, o1; + int32 o, o1; o = -1; /* @@ -544,7 +575,7 @@ { Type *lt; Node *n1, *n2; - long o; + int32 o; lt = l->type; if(lt == T) @@ -659,7 +690,7 @@ Type *t1, *t2; int i, j, k; Node *n1; - long w; + int32 w; t1 = n->left->type; if(n->right == Z) @@ -692,7 +723,7 @@ if(w < 1 || n->left->type->link == T || n->left->type->link->width < 1) goto bad; n->type = types[ewidth[TIND] <= ewidth[TLONG]? TLONG: TVLONG]; - if(1 && ewidth[TIND] > ewidth[TLONG]){ + if(0 && ewidth[TIND] > ewidth[TLONG]){ n1 = new1(OXXX, Z, Z); *n1 = *n; n->op = OCAST; @@ -769,7 +800,7 @@ void simplifyshift(Node *n) { - ulong c3; + uint32 c3; int o, s1, s2, c1, c2; if(!typechlp[n->type->etype]) @@ -815,7 +846,7 @@ /* if(debug['h']) - print("%.3o %ld %ld %d #%.lux\n", + print("%.3o %d %d %d #%.ux\n", (s1<<3)|s2, c1, c2, topbit(c3), c3); */ @@ -1014,7 +1045,7 @@ * return log(n) if n is a power of 2 constant */ int -log2(uvlong v) +xlog2(uvlong v) { int s, i; uvlong m; @@ -1041,14 +1072,14 @@ if(typefd[n->type->etype]) goto bad; - return log2(n->vconst); + return xlog2(n->vconst); bad: return -1; } int -topbit(ulong v) +topbit(uint32 v) { int i; @@ -1130,7 +1161,7 @@ } int -bitno(long b) +bitno(int32 b) { int i; @@ -1141,10 +1172,10 @@ return 0; } -long -typebitor(long a, long b) +int32 +typebitor(int32 a, int32 b) { - long c; + int32 c; c = a | b; if(a & b) @@ -1247,10 +1278,10 @@ errorexit(); } -ulong thash1 = 0x2edab8c9; -ulong thash2 = 0x1dc74fb8; -ulong thash3 = 0x1f241331; -ulong thash[NALLTYPES]; +uint32 thash1 = 0x2edab8c9; +uint32 thash2 = 0x1dc74fb8; +uint32 thash3 = 0x1f241331; +uint32 thash[NALLTYPES]; Init thashinit[] = { TXXX, 0x17527bbd, 0, @@ -1430,6 +1461,7 @@ ODWHILE, 0, "DWHILE", OENUM, 0, "ENUM", OEQ, 0, "EQ", + OEXREG, 0, "EXREG", OFOR, 0, "FOR", OFUNC, 0, "FUNC", OGE, 0, "GE", @@ -1490,105 +1522,105 @@ }; /* OEQ, ONE, OLE, OLS, OLT, OLO, OGE, OHS, OGT, OHI */ -char comrel[12] = +uchar comrel[12] = { ONE, OEQ, OGT, OHI, OGE, OHS, OLT, OLO, OLE, OLS, }; -char invrel[12] = +uchar invrel[12] = { OEQ, ONE, OGE, OHS, OGT, OHI, OLE, OLS, OLT, OLO, }; -char logrel[12] = +uchar logrel[12] = { OEQ, ONE, OLS, OLS, OLO, OLO, OHS, OHS, OHI, OHI, }; -char typei[NTYPE]; +uchar typei[NTYPE]; int typeiinit[] = { TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TVLONG, TUVLONG, -1, }; -char typeu[NTYPE]; +uchar typeu[NTYPE]; int typeuinit[] = { TUCHAR, TUSHORT, TUINT, TULONG, TUVLONG, TIND, -1, }; -char typesuv[NTYPE]; +uchar typesuv[NTYPE]; int typesuvinit[] = { TVLONG, TUVLONG, TSTRUCT, TUNION, -1, }; -char typeilp[NTYPE]; +uchar typeilp[NTYPE]; int typeilpinit[] = { TINT, TUINT, TLONG, TULONG, TIND, -1 }; -char typechl[NTYPE]; -char typechlv[NTYPE]; -char typechlvp[NTYPE]; +uchar typechl[NTYPE]; +uchar typechlv[NTYPE]; +uchar typechlvp[NTYPE]; int typechlinit[] = { TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, -1, }; -char typechlp[NTYPE]; +uchar typechlp[NTYPE]; int typechlpinit[] = { TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TIND, -1, }; -char typechlpfd[NTYPE]; +uchar typechlpfd[NTYPE]; int typechlpfdinit[] = { TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TFLOAT, TDOUBLE, TIND, -1, }; -char typec[NTYPE]; +uchar typec[NTYPE]; int typecinit[] = { TCHAR, TUCHAR, -1 }; -char typeh[NTYPE]; +uchar typeh[NTYPE]; int typehinit[] = { TSHORT, TUSHORT, -1, }; -char typeil[NTYPE]; +uchar typeil[NTYPE]; int typeilinit[] = { TINT, TUINT, TLONG, TULONG, -1, }; -char typev[NTYPE]; +uchar typev[NTYPE]; int typevinit[] = { TVLONG, TUVLONG, -1, }; -char typefd[NTYPE]; +uchar typefd[NTYPE]; int typefdinit[] = { TFLOAT, TDOUBLE, -1, }; -char typeaf[NTYPE]; +uchar typeaf[NTYPE]; int typeafinit[] = { TFUNC, TARRAY, -1, }; -char typesu[NTYPE]; +uchar typesu[NTYPE]; int typesuinit[] = { TSTRUCT, TUNION, -1, }; -long tasign[NTYPE]; +int32 tasign[NTYPE]; Init tasigninit[] = { TCHAR, BNUMBER, 0, @@ -1609,7 +1641,7 @@ -1, 0, 0, }; -long tasadd[NTYPE]; +int32 tasadd[NTYPE]; Init tasaddinit[] = { TCHAR, BNUMBER, 0, @@ -1628,7 +1660,7 @@ -1, 0, 0, }; -long tcast[NTYPE]; +int32 tcast[NTYPE]; Init tcastinit[] = { TCHAR, BNUMBER|BIND|BVOID, 0, @@ -1650,7 +1682,7 @@ -1, 0, 0, }; -long tadd[NTYPE]; +int32 tadd[NTYPE]; Init taddinit[] = { TCHAR, BNUMBER|BIND, 0, @@ -1669,7 +1701,7 @@ -1, 0, 0, }; -long tsub[NTYPE]; +int32 tsub[NTYPE]; Init tsubinit[] = { TCHAR, BNUMBER, 0, @@ -1688,7 +1720,7 @@ -1, 0, 0, }; -long tmul[NTYPE]; +int32 tmul[NTYPE]; Init tmulinit[] = { TCHAR, BNUMBER, 0, @@ -1706,7 +1738,7 @@ -1, 0, 0, }; -long tand[NTYPE]; +int32 tand[NTYPE]; Init tandinit[] = { TCHAR, BINTEGER, 0, @@ -1722,7 +1754,7 @@ -1, 0, 0, }; -long trel[NTYPE]; +int32 trel[NTYPE]; Init trelinit[] = { TCHAR, BNUMBER, 0, @@ -1741,32 +1773,32 @@ -1, 0, 0, }; -long tfunct[1] = +int32 tfunct[1] = { BFUNC, }; -long tindir[1] = +int32 tindir[1] = { BIND, }; -long tdot[1] = +int32 tdot[1] = { BSTRUCT|BUNION, }; -long tnot[1] = +int32 tnot[1] = { BNUMBER|BIND, }; -long targ[1] = +int32 targ[1] = { BNUMBER|BIND|BSTRUCT|BUNION, }; -char tab[NTYPE][NTYPE] = +uchar tab[NTYPE][NTYPE] = { /*TXXX*/ { 0, }, diff -r d8d00747375b sys/src/cmd/ld/data.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/src/cmd/ld/data.c Mon Nov 14 17:35:25 2011 +0100 @@ -0,0 +1,1030 @@ +// 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. + +// Data layout and relocation. + +#include "l.h" +#include "../ld/lib.h" +#include "../ld/elf.h" +#include "../ld/pe.h" + +void dynreloc(void); +static vlong addaddrplus4(Sym *s, Sym *t, int32 add); + +/* + * divide-and-conquer list-link + * sort of Sym* structures. + * Used for the data block. + */ +int +datcmp(Sym *s1, Sym *s2) +{ + if(s1->type != s2->type) + return (int)s1->type - (int)s2->type; + if(s1->size != s2->size) { + if(s1->size < s2->size) + return -1; + return +1; + } + return strcmp(s1->name, s2->name); +} + +Sym* +datsort(Sym *l) +{ + Sym *l1, *l2, *le; + + if(l == 0 || l->next == 0) + return l; + + l1 = l; + l2 = l; + for(;;) { + l2 = l2->next; + if(l2 == 0) + break; + l2 = l2->next; + if(l2 == 0) + break; + l1 = l1->next; + } + + l2 = l1->next; + l1->next = 0; + l1 = datsort(l); + l2 = datsort(l2); + + /* set up lead element */ + if(datcmp(l1, l2) < 0) { + l = l1; + l1 = l1->next; + } else { + l = l2; + l2 = l2->next; + } + le = l; + + for(;;) { + if(l1 == 0) { + while(l2) { + le->next = l2; + le = l2; + l2 = l2->next; + } + le->next = 0; + break; + } + if(l2 == 0) { + while(l1) { + le->next = l1; + le = l1; + l1 = l1->next; + } + break; + } + if(datcmp(l1, l2) < 0) { + le->next = l1; + le = l1; + l1 = l1->next; + } else { + le->next = l2; + le = l2; + l2 = l2->next; + } + } + le->next = 0; + return l; +} + +Reloc* +addrel(Sym *s) +{ + if(s->nr >= s->maxr) { + if(s->maxr == 0) + s->maxr = 4; + else + s->maxr <<= 1; + s->r = realloc(s->r, s->maxr*sizeof s->r[0]); + if(s->r == 0) { + diag("out of memory"); + errorexit(); + } + memset(s->r+s->nr, 0, (s->maxr-s->nr)*sizeof s->r[0]); + } + return &s->r[s->nr++]; +} + +void +relocsym(Sym *s) +{ + Reloc *r; + Prog p; + int32 i, off, siz, fl; + vlong o; + uchar *cast; + + cursym = s; + memset(&p, 0, sizeof p); + for(r=s->r; rr+s->nr; r++) { + off = r->off; + siz = r->siz; + if(off < 0 || off+(siz&~Rbig) > s->np) { + diag("%s: invalid relocation %d+%d not in [%d,%d)", s->name, off, siz&~Rbig, 0, s->np); + continue; + } + if(r->sym != S && (r->sym->type == 0 || r->sym->type == SXREF)) { + diag("%s: not defined", r->sym->name); + continue; + } + if(r->type >= 256) + continue; + + if(r->sym != S && r->sym->type == SDYNIMPORT) + diag("unhandled relocation for %s (type %d rtype %d)", r->sym->name, r->sym->type, r->type); + + if(r->sym != S && !r->sym->reachable) + diag("unreachable sym in relocation: %s %s", s->name, r->sym->name); + + switch(r->type) { + default: + o = 0; + if(archreloc(r, s, &o) < 0) + diag("unknown reloc %d", r->type); + break; + case D_ADDR: + o = symaddr(r->sym) + r->add; + break; + case D_PCREL: + // r->sym can be null when CALL $(constant) is transformed from absoulte PC to relative PC call. + o = 0; + if(r->sym) + o += symaddr(r->sym); + o += r->add - (s->value + r->off + r->siz); + break; + case D_SIZE: + o = r->sym->size + r->add; + break; + } +//print("relocate %s %p %s => %p %p %p %p [%p]\n", s->name, s->value+off, r->sym ? r->sym->name : "", (void*)symaddr(r->sym), (void*)s->value, (void*)r->off, (void*)r->siz, (void*)o); + switch(siz) { + default: + cursym = s; + diag("bad reloc size %#ux for %s", siz, r->sym->name); + case 4 + Rbig: + fl = o; + s->p[off] = fl>>24; + s->p[off+1] = fl>>16; + s->p[off+2] = fl>>8; + s->p[off+3] = fl; + break; + case 4 + Rlittle: + fl = o; + s->p[off] = fl; + s->p[off+1] = fl>>8; + s->p[off+2] = fl>>16; + s->p[off+3] = fl>>24; + break; + case 4: + fl = o; + cast = (uchar*)&fl; + for(i=0; i<4; i++) + s->p[off+i] = cast[inuxi4[i]]; + break; + case 8: + cast = (uchar*)&o; + for(i=0; i<8; i++) + s->p[off+i] = cast[inuxi8[i]]; + break; + } + } +} + +void +reloc(void) +{ + Sym *s; + + if(debug['v']) + Bprint(&bso, "%5.2f reloc\n", cputime()); + Bflush(&bso); + + for(s=textp; s!=S; s=s->next) + relocsym(s); + for(s=datap; s!=S; s=s->next) + relocsym(s); +} + +void +dynrelocsym(Sym *s) +{ + Reloc *r; + + if(HEADTYPE == Hwindows) { + Sym *rel, *targ; + + rel = lookup(".rel", 0); + if(s == rel) + return; + for(r=s->r; rr+s->nr; r++) { + targ = r->sym; + if(r->sym->plt == -2 && r->sym->got != -2) { // make dynimport JMP table for PE object files. + targ->plt = rel->size; + r->sym = rel; + r->add = targ->plt; + + // jmp *addr + if(thechar == '8') { + adduint8(rel, 0xff); + adduint8(rel, 0x25); + addaddr(rel, targ); + adduint8(rel, 0x90); + adduint8(rel, 0x90); + } else { + adduint8(rel, 0xff); + adduint8(rel, 0x24); + adduint8(rel, 0x25); + addaddrplus4(rel, targ, 0); + adduint8(rel, 0x90); + } + } else if(r->sym->plt >= 0) { + r->sym = rel; + r->add = targ->plt; + } + } + return; + } + + for(r=s->r; rr+s->nr; r++) + if(r->sym->type == SDYNIMPORT || r->type >= 256) + adddynrel(s, r); +} + +void +dynreloc(void) +{ + Sym *s; + + // -d supresses dynamic loader format, so we may as well not + // compute these sections or mark their symbols as reachable. + if(debug['d'] && HEADTYPE != Hwindows) + return; + if(debug['v']) + Bprint(&bso, "%5.2f reloc\n", cputime()); + Bflush(&bso); + + for(s=textp; s!=S; s=s->next) + dynrelocsym(s); + for(s=datap; s!=S; s=s->next) + dynrelocsym(s); + if(iself) + elfdynhash(); +} + +void +symgrow(Sym *s, int32 siz) +{ + if(s->np >= siz) + return; + + if(s->maxp < siz) { + if(s->maxp == 0) + s->maxp = 8; + while(s->maxp < siz) + s->maxp <<= 1; + s->p = realloc(s->p, s->maxp); + if(s->p == nil) { + diag("out of memory"); + errorexit(); + } + memset(s->p+s->np, 0, s->maxp-s->np); + } + s->np = siz; +} + +void +savedata(Sym *s, Prog *p, char *pn) +{ + int32 off, siz, i, fl; + uchar *cast; + vlong o; + Reloc *r; + + off = p->from.offset; + siz = p->datasize; + if(off < 0 || siz < 0 || off >= 1<<30 || siz >= 100) + mangle(pn); + symgrow(s, off+siz); + + switch(p->to.type) { + default: + diag("bad data: %P", p); + break; + + case D_FCONST: + switch(siz) { + default: + case 4: + fl = ieeedtof(&p->to.ieee); + cast = (uchar*)&fl; + for(i=0; i<4; i++) + s->p[off+i] = cast[fnuxi4[i]]; + break; + case 8: + cast = (uchar*)&p->to.ieee; + for(i=0; i<8; i++) + s->p[off+i] = cast[fnuxi8[i]]; + break; + } + break; + + case D_SCONST: + for(i=0; ip[off+i] = p->to.scon[i]; + break; + + case D_CONST: + if(p->to.sym) + goto Addr; + o = p->to.offset; + fl = o; + cast = (uchar*)&fl; + switch(siz) { + default: + diag("bad nuxi %d\n%P", siz, p); + break; + case 1: + s->p[off] = cast[inuxi1[0]]; + break; + case 2: + for(i=0; i<2; i++) + s->p[off+i] = cast[inuxi2[i]]; + break; + case 4: + for(i=0; i<4; i++) + s->p[off+i] = cast[inuxi4[i]]; + break; + case 8: + cast = (uchar*)&o; + for(i=0; i<8; i++) + s->p[off+i] = cast[inuxi8[i]]; + break; + } + break; + + case D_ADDR: + case D_SIZE: + Addr: + r = addrel(s); + r->off = off; + r->siz = siz; + r->sym = p->to.sym; + r->type = p->to.type; + if(r->type != D_SIZE) + r->type = D_ADDR; + r->add = p->to.offset; + break; + } +} + +static void +blk(Sym *allsym, int32 addr, int32 size) +{ + Sym *sym; + int32 eaddr; + uchar *p, *ep; + + for(sym = allsym; sym != nil; sym = sym->next) + if(!(sym->type&SSUB) && sym->value >= addr) + break; + + eaddr = addr+size; + for(; sym != nil; sym = sym->next) { + if(sym->type&SSUB) + continue; + if(sym->value >= eaddr) + break; + if(sym->value < addr) { + diag("phase error: addr=%#llx but sym=%#llx type=%d", (vlong)addr, (vlong)sym->value, sym->type); + errorexit(); + } + cursym = sym; + for(; addr < sym->value; addr++) + cput(0); + p = sym->p; + ep = p + sym->np; + while(p < ep) + cput(*p++); + addr += sym->np; + for(; addr < sym->value+sym->size; addr++) + cput(0); + if(addr != sym->value+sym->size) { + diag("phase error: addr=%#llx value+size=%#llx", (vlong)addr, (vlong)sym->value+sym->size); + errorexit(); + } + } + + for(; addr < eaddr; addr++) + cput(0); + cflush(); +} + +void +codeblk(int32 addr, int32 size) +{ + Sym *sym; + int32 eaddr, n, epc; + Prog *p; + uchar *q; + + if(debug['a']) + Bprint(&bso, "codeblk [%#x,%#x) at offset %#llx\n", addr, addr+size, cpos()); + + blk(textp, addr, size); + + /* again for printing */ + if(!debug['a']) + return; + + for(sym = textp; sym != nil; sym = sym->next) { + if(!sym->reachable) + continue; + if(sym->value >= addr) + break; + } + + eaddr = addr + size; + for(; sym != nil; sym = sym->next) { + if(!sym->reachable) + continue; + if(sym->value >= eaddr) + break; + + if(addr < sym->value) { + Bprint(&bso, "%-20s %.8llux|", "_", (vlong)addr); + for(; addr < sym->value; addr++) + Bprint(&bso, " %.2ux", 0); + Bprint(&bso, "\n"); + } + p = sym->text; + if(p == nil) { + Bprint(&bso, "%.6llux\t%-20s | foreign text\n", (vlong)addr, sym->name); + n = sym->size; + q = sym->p; + + while(n >= 16) { + Bprint(&bso, "%.6ux\t%-20.16I\n", addr, q); + addr += 16; + q += 16; + n -= 16; + } + if(n > 0) + Bprint(&bso, "%.6ux\t%-20.*I\n", addr, (int)n, q); + addr += n; + continue; + } + + Bprint(&bso, "%.6llux\t%-20s | %P\n", (vlong)sym->value, sym->name, p); + for(p = p->link; p != P; p = p->link) { + if(p->link != P) + epc = p->link->pc; + else + epc = sym->value + sym->size; + Bprint(&bso, "%.6llux\t", (uvlong)p->pc); + q = sym->p + p->pc - sym->value; + n = epc - p->pc; + Bprint(&bso, "%-20.*I | %P\n", (int)n, q, p); + addr += n; + } + } + + if(addr < eaddr) { + Bprint(&bso, "%-20s %.8llux|", "_", (vlong)addr); + for(; addr < eaddr; addr++) + Bprint(&bso, " %.2ux", 0); + } + Bflush(&bso); +} + +void +datblk(int32 addr, int32 size) +{ + Sym *sym; + int32 eaddr; + uchar *p, *ep; + + if(debug['a']) + Bprint(&bso, "datblk [%#x,%#x) at offset %#llx\n", addr, addr+size, cpos()); + + blk(datap, addr, size); + + /* again for printing */ + if(!debug['a']) + return; + + for(sym = datap; sym != nil; sym = sym->next) + if(sym->value >= addr) + break; + + eaddr = addr + size; + for(; sym != nil; sym = sym->next) { + if(sym->value >= eaddr) + break; + if(addr < sym->value) { + Bprint(&bso, "%-20s %.8ux| 00 ...\n", "(pre-pad)", addr); + addr = sym->value; + } + Bprint(&bso, "%-20s %.8ux|", sym->name, (uint)addr); + p = sym->p; + ep = p + sym->np; + while(p < ep) + Bprint(&bso, " %.2ux", *p++); + addr += sym->np; + for(; addr < sym->value+sym->size; addr++) + Bprint(&bso, " %.2ux", 0); + Bprint(&bso, "\n"); + } + + if(addr < eaddr) + Bprint(&bso, "%-20s %.8ux| 00 ...\n", "(post-pad)", (uint)addr); + Bprint(&bso, "%-20s %.8ux|\n", "", (uint)eaddr); +} + +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; + int32 r; + + if(s->type == 0) + s->type = SDATA; + s->reachable = 1; + r = s->size; + n = strlen(str)+1; + if(strcmp(s->name, ".shstrtab") == 0) + elfsetstring(str, r); + symgrow(s, r+n); + memmove(s->p+r, str, n); + s->size += n; + return r; +} + +vlong +adduintxx(Sym *s, uint64 v, int wid) +{ + int32 i, r, fl; + vlong o; + uchar *cast; + + if(s->type == 0) + s->type = SDATA; + s->reachable = 1; + r = s->size; + s->size += wid; + symgrow(s, s->size); + assert(r+wid <= s->size); + fl = v; + cast = (uchar*)&fl; + switch(wid) { + case 1: + s->p[r] = cast[inuxi1[0]]; + break; + case 2: + for(i=0; i<2; i++) + s->p[r+i] = cast[inuxi2[i]]; + break; + case 4: + for(i=0; i<4; i++) + s->p[r+i] = cast[inuxi4[i]]; + break; + case 8: + o = v; + cast = (uchar*)&o; + for(i=0; i<8; i++) + s->p[r+i] = cast[inuxi8[i]]; + break; + } + 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 +addaddrplus(Sym *s, Sym *t, int32 add) +{ + vlong i; + Reloc *r; + + if(s->type == 0) + s->type = SDATA; + s->reachable = 1; + i = s->size; + s->size += PtrSize; + symgrow(s, s->size); + r = addrel(s); + r->sym = t; + r->off = i; + r->siz = PtrSize; + r->type = D_ADDR; + r->add = add; + return i; +} + +static vlong +addaddrplus4(Sym *s, Sym *t, int32 add) +{ + vlong i; + Reloc *r; + + if(s->type == 0) + s->type = SDATA; + s->reachable = 1; + i = s->size; + s->size += 4; + symgrow(s, s->size); + r = addrel(s); + r->sym = t; + r->off = i; + r->siz = 4; + r->type = D_ADDR; + r->add = add; + return i; +} + +vlong +addpcrelplus(Sym *s, Sym *t, int32 add) +{ + vlong i; + Reloc *r; + + if(s->type == 0) + s->type = SDATA; + s->reachable = 1; + i = s->size; + s->size += 4; + symgrow(s, s->size); + r = addrel(s); + r->sym = t; + r->off = i; + r->add = add; + r->type = D_PCREL; + r->siz = 4; + return i; +} + +vlong +addaddr(Sym *s, Sym *t) +{ + return addaddrplus(s, t, 0); +} + +vlong +addsize(Sym *s, Sym *t) +{ + vlong i; + Reloc *r; + + if(s->type == 0) + s->type = SDATA; + s->reachable = 1; + i = s->size; + s->size += PtrSize; + symgrow(s, s->size); + r = addrel(s); + r->sym = t; + r->off = i; + r->siz = PtrSize; + r->type = D_SIZE; + return i; +} + +void +dodata(void) +{ + int32 t, datsize; + Section *sect; + Sym *s, *last, **l; + + if(debug['v']) + Bprint(&bso, "%5.2f dodata\n", cputime()); + Bflush(&bso); + + last = nil; + datap = nil; + + for(s=allsym; s!=S; s=s->allsym) { + if(!s->reachable || s->special) + continue; + if(STEXT < s->type && s->type < SXREF) { + if(last == nil) + datap = s; + else + last->next = s; + s->next = nil; + last = s; + } + } + + for(s = datap; s != nil; s = s->next) { + if(s->np > 0 && s->type == SBSS) + s->type = SDATA; + if(s->np > s->size) + diag("%s: initialize bounds (%lld < %d)", + s->name, (vlong)s->size, s->np); + } + + /* + * now that we have the datap list, but before we start + * to assign addresses, record all the necessary + * dynamic relocations. these will grow the relocation + * symbol, which is itself data. + */ + dynreloc(); + + /* some symbols may no longer belong in datap (Mach-O) */ + for(l=&datap; (s=*l) != nil; ) { + if(s->type <= STEXT || SXREF <= s->type) + *l = s->next; + else + l = &s->next; + } + *l = nil; + + datap = datsort(datap); + + /* + * allocate data sections. list is sorted by type, + * so we can just walk it for each piece we want to emit. + */ + + /* read-only data */ + sect = addsection(&segtext, ".rodata", 04); + sect->vaddr = 0; + datsize = 0; + s = datap; + for(; s != nil && s->type < SSYMTAB; s = s->next) { + s->type = SRODATA; + s->value = datsize; + datsize += rnd(s->size, PtrSize); + } + sect->len = datsize - sect->vaddr; + + /* gosymtab */ + sect = addsection(&segtext, ".gosymtab", 04); + sect->vaddr = datsize; + for(; s != nil && s->type < SPCLNTAB; s = s->next) { + s->type = SRODATA; + s->value = datsize; + datsize += s->size; + } + sect->len = datsize - sect->vaddr; + datsize = rnd(datsize, PtrSize); + + /* gopclntab */ + sect = addsection(&segtext, ".gopclntab", 04); + sect->vaddr = datsize; + for(; s != nil && s->type < SELFROSECT; s = s->next) { + s->type = SRODATA; + s->value = datsize; + datsize += s->size; + } + sect->len = datsize - sect->vaddr; + datsize = rnd(datsize, PtrSize); + + /* read-only ELF sections */ + for(; s != nil && s->type < SELFSECT; s = s->next) { + sect = addsection(&segtext, s->name, 04); + sect->vaddr = datsize; + s->type = SRODATA; + s->value = datsize; + datsize += rnd(s->size, PtrSize); + sect->len = datsize - sect->vaddr; + } + + /* writable ELF sections */ + datsize = 0; + for(; s != nil && s->type < SDATA; s = s->next) { + sect = addsection(&segdata, s->name, 06); + sect->vaddr = datsize; + s->type = SDATA; + s->value = datsize; + datsize += rnd(s->size, PtrSize); + sect->len = datsize - sect->vaddr; + } + + /* data */ + sect = addsection(&segdata, ".data", 06); + sect->vaddr = datsize; + for(; s != nil && s->type < SBSS; s = s->next) { + s->type = SDATA; + t = s->size; + if(t == 0 && s->name[0] != '.') { + diag("%s: no size", s->name); + t = 1; + } + if(t >= PtrSize) + t = rnd(t, PtrSize); + else if(t > 2) + t = rnd(t, 4); + if(t & 1) { + ; + } else if(t & 2) + datsize = rnd(datsize, 2); + else if(t & 4) + datsize = rnd(datsize, 4); + else + datsize = rnd(datsize, 8); + s->value = datsize; + datsize += t; + } + sect->len = datsize - sect->vaddr; + + /* bss */ + sect = addsection(&segdata, ".bss", 06); + sect->vaddr = datsize; + for(; s != nil; s = s->next) { + if(s->type != SBSS) { + cursym = s; + diag("unexpected symbol type %d", s->type); + } + t = s->size; + if(t >= PtrSize) + t = rnd(t, PtrSize); + else if(t > 2) + t = rnd(t, 4); + if(t & 1) { + ; + } else if(t & 2) + datsize = rnd(datsize, 2); + else if(t & 4) + datsize = rnd(datsize, 4); + else + datsize = rnd(datsize, 8); + s->value = datsize; + datsize += t; + } + sect->len = datsize - sect->vaddr; +} + +// assign addresses to text +void +textaddress(void) +{ + uvlong va; + Prog *p; + Section *sect; + Sym *sym, *sub; + + addsection(&segtext, ".text", 05); + + // Assign PCs in text segment. + // Could parallelize, by assigning to text + // and then letting threads copy down, but probably not worth it. + sect = segtext.sect; + va = INITTEXT; + sect->vaddr = va; + for(sym = textp; sym != nil; sym = sym->next) { + if(sym->type & SSUB) + continue; + sym->value = 0; + for(sub = sym; sub != S; sub = sub->sub) { + sub->value += va; + for(p = sub->text; p != P; p = p->link) + p->pc += sub->value; + } + if(sym->size == 0 && sym->sub != S) { + cursym = sym; + } + va += sym->size; + } + sect->len = va - sect->vaddr; +} + +// assign addresses +void +address(void) +{ + Section *s, *text, *data, *rodata, *symtab, *pclntab; + Sym *sym, *sub; + uvlong va; + + va = INITTEXT; + segtext.rwx = 05; + segtext.vaddr = va; + segtext.fileoff = HEADR; + for(s=segtext.sect; s != nil; s=s->next) { + s->vaddr = va; + va += rnd(s->len, PtrSize); + } + segtext.len = va - INITTEXT; + segtext.filelen = segtext.len; + + va = rnd(va, INITRND); + + segdata.rwx = 06; + segdata.vaddr = va; + segdata.fileoff = va - segtext.vaddr + segtext.fileoff; + segdata.filelen = 0; + if(HEADTYPE == Hwindows) + segdata.fileoff = segtext.fileoff + rnd(segtext.len, PEFILEALIGN); + if(HEADTYPE == Hplan9x32) + segdata.fileoff = segtext.fileoff + segtext.filelen; + data = nil; + for(s=segdata.sect; s != nil; s=s->next) { + s->vaddr = va; + va += s->len; + segdata.filelen += s->len; + segdata.len = va - segdata.vaddr; + if(strcmp(s->name, ".data") == 0) + data = s; + } + segdata.filelen -= data->next->len; // deduct .bss + + text = segtext.sect; + rodata = text->next; + symtab = rodata->next; + pclntab = symtab->next; + + for(sym = datap; sym != nil; sym = sym->next) { + cursym = sym; + if(sym->type < SDATA) + sym->value += rodata->vaddr; + else + sym->value += segdata.sect->vaddr; + for(sub = sym->sub; sub != nil; sub = sub->sub) + sub->value += sym->value; + } + + xdefine("text", STEXT, text->vaddr); + xdefine("etext", STEXT, text->vaddr + text->len); + xdefine("rodata", SRODATA, rodata->vaddr); + xdefine("erodata", SRODATA, rodata->vaddr + rodata->len); + xdefine("symtab", SRODATA, symtab->vaddr); + xdefine("esymtab", SRODATA, symtab->vaddr + symtab->len); + xdefine("pclntab", SRODATA, pclntab->vaddr); + xdefine("epclntab", SRODATA, pclntab->vaddr + pclntab->len); + xdefine("data", SBSS, data->vaddr); + xdefine("edata", SBSS, data->vaddr + data->len); + xdefine("end", SBSS, segdata.vaddr + segdata.len); +} diff -r d8d00747375b sys/src/cmd/ld/dwarf.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/src/cmd/ld/dwarf.c Mon Nov 14 17:35:25 2011 +0100 @@ -0,0 +1,2592 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// TODO/NICETOHAVE: +// - eliminate DW_CLS_ if not used +// - package info in compilation units +// - assign global variables and types to their packages +// - gdb uses c syntax, meaning clumsy quoting is needed for go identifiers. eg +// ptype struct '[]uint8' and qualifiers need to be quoted away +// - lexical scoping is lost, so gdb gets confused as to which 'main.i' you mean. +// - file:line info for variables +// - make strings a typedef so prettyprinters can see the underlying string type +// +#include "l.h" +#include "lib.h" +#include "../ld/dwarf.h" +#include "../ld/dwarf_defs.h" +#include "../ld/elf.h" +#include "../ld/macho.h" +#include "../ld/pe.h" + +/* + * Offsets and sizes of the debug_* sections in the cout file. + */ + +static vlong abbrevo; +static vlong abbrevsize; +static vlong lineo; +static vlong linesize; +static vlong infoo; // also the base for DWDie->offs and reference attributes. +static vlong infosize; +static vlong frameo; +static vlong framesize; +static vlong pubnameso; +static vlong pubnamessize; +static vlong pubtypeso; +static vlong pubtypessize; +static vlong arangeso; +static vlong arangessize; +static vlong gdbscripto; +static vlong gdbscriptsize; + +static char gdbscript[1024]; + +/* + * Basic I/O + */ + +static void +addrput(vlong addr) +{ + switch(PtrSize) { + case 4: + LPUT(addr); + break; + case 8: + VPUT(addr); + break; + } +} + +static int +uleb128enc(uvlong v, char* dst) +{ + uint8 c, len; + + len = 0; + do { + c = v & 0x7f; + v >>= 7; + if (v) + c |= 0x80; + if (dst) + *dst++ = c; + len++; + } while (c & 0x80); + return len; +}; + +static int +sleb128enc(vlong v, char *dst) +{ + uint8 c, s, len; + + len = 0; + do { + c = v & 0x7f; + s = v & 0x40; + v >>= 7; + if ((v != -1 || !s) && (v != 0 || s)) + c |= 0x80; + if (dst) + *dst++ = c; + len++; + } while(c & 0x80); + return len; +} + +static void +uleb128put(vlong v) +{ + char buf[10]; + strnput(buf, uleb128enc(v, buf)); +} + +static void +sleb128put(vlong v) +{ + char buf[10]; + strnput(buf, sleb128enc(v, buf)); +} + +/* + * Defining Abbrevs. This is hardcoded, and there will be + * only a handful of them. The DWARF spec places no restriction on + * the ordering of atributes in the Abbrevs and DIEs, and we will + * always write them out in the order of declaration in the abbrev. + * This implementation relies on tag, attr < 127, so they serialize as + * a char. Higher numbered user-defined tags or attributes can be used + * for storing internal data but won't be serialized. + */ +typedef struct DWAttrForm DWAttrForm; +struct DWAttrForm { + uint8 attr; + uint8 form; +}; + +// Index into the abbrevs table below. +// Keep in sync with ispubname() and ispubtype() below. +// ispubtype considers >= NULLTYPE public +enum +{ + DW_ABRV_NULL, + DW_ABRV_COMPUNIT, + DW_ABRV_FUNCTION, + DW_ABRV_VARIABLE, + DW_ABRV_AUTO, + DW_ABRV_PARAM, + DW_ABRV_STRUCTFIELD, + DW_ABRV_FUNCTYPEPARAM, + DW_ABRV_DOTDOTDOT, + DW_ABRV_ARRAYRANGE, + DW_ABRV_NULLTYPE, + DW_ABRV_BASETYPE, + DW_ABRV_ARRAYTYPE, + DW_ABRV_CHANTYPE, + DW_ABRV_FUNCTYPE, + DW_ABRV_IFACETYPE, + DW_ABRV_MAPTYPE, + DW_ABRV_PTRTYPE, + DW_ABRV_SLICETYPE, + DW_ABRV_STRINGTYPE, + DW_ABRV_STRUCTTYPE, + DW_ABRV_TYPEDECL, + DW_NABRV +}; + +typedef struct DWAbbrev DWAbbrev; +static struct DWAbbrev { + uint8 tag; + uint8 children; + DWAttrForm attr[30]; +} abbrevs[DW_NABRV] = { + /* The mandatory DW_ABRV_NULL entry. */ + { 0 }, + /* COMPUNIT */ + { + DW_TAG_compile_unit, DW_CHILDREN_yes, + DW_AT_name, DW_FORM_string, + DW_AT_language, DW_FORM_data1, + DW_AT_low_pc, DW_FORM_addr, + DW_AT_high_pc, DW_FORM_addr, + DW_AT_stmt_list, DW_FORM_data4, + 0, 0 + }, + /* FUNCTION */ + { + DW_TAG_subprogram, DW_CHILDREN_yes, + DW_AT_name, DW_FORM_string, + DW_AT_low_pc, DW_FORM_addr, + DW_AT_high_pc, DW_FORM_addr, + DW_AT_external, DW_FORM_flag, + 0, 0 + }, + /* VARIABLE */ + { + DW_TAG_variable, DW_CHILDREN_no, + DW_AT_name, DW_FORM_string, + DW_AT_location, DW_FORM_block1, + DW_AT_type, DW_FORM_ref_addr, + DW_AT_external, DW_FORM_flag, + 0, 0 + }, + /* AUTO */ + { + DW_TAG_variable, DW_CHILDREN_no, + DW_AT_name, DW_FORM_string, + DW_AT_location, DW_FORM_block1, + DW_AT_type, DW_FORM_ref_addr, + 0, 0 + }, + /* PARAM */ + { + DW_TAG_formal_parameter, DW_CHILDREN_no, + DW_AT_name, DW_FORM_string, + DW_AT_location, DW_FORM_block1, + DW_AT_type, DW_FORM_ref_addr, + 0, 0 + }, + /* STRUCTFIELD */ + { + DW_TAG_member, DW_CHILDREN_no, + DW_AT_name, DW_FORM_string, + DW_AT_data_member_location, DW_FORM_block1, + DW_AT_type, DW_FORM_ref_addr, + 0, 0 + }, + /* FUNCTYPEPARAM */ + { + DW_TAG_formal_parameter, DW_CHILDREN_no, + // No name! + DW_AT_type, DW_FORM_ref_addr, + 0, 0 + }, + + /* DOTDOTDOT */ + { + DW_TAG_unspecified_parameters, DW_CHILDREN_no, + 0, 0 + }, + /* ARRAYRANGE */ + { + DW_TAG_subrange_type, DW_CHILDREN_no, + // No name! + DW_AT_type, DW_FORM_ref_addr, + DW_AT_upper_bound, DW_FORM_data1, + 0, 0 + }, + + // Below here are the types considered public by ispubtype + /* NULLTYPE */ + { + DW_TAG_unspecified_type, DW_CHILDREN_no, + DW_AT_name, DW_FORM_string, + 0, 0 + }, + /* BASETYPE */ + { + DW_TAG_base_type, DW_CHILDREN_no, + DW_AT_name, DW_FORM_string, + DW_AT_encoding, DW_FORM_data1, + DW_AT_byte_size, DW_FORM_data1, + 0, 0 + }, + /* ARRAYTYPE */ + // child is subrange with upper bound + { + DW_TAG_array_type, DW_CHILDREN_yes, + DW_AT_name, DW_FORM_string, + DW_AT_type, DW_FORM_ref_addr, + DW_AT_byte_size, DW_FORM_udata, + 0, 0 + }, + + /* CHANTYPE */ + { + DW_TAG_typedef, DW_CHILDREN_no, + DW_AT_name, DW_FORM_string, + DW_AT_type, DW_FORM_ref_addr, + 0, 0 + }, + + /* FUNCTYPE */ + { + DW_TAG_subroutine_type, DW_CHILDREN_yes, + DW_AT_name, DW_FORM_string, +// DW_AT_type, DW_FORM_ref_addr, + 0, 0 + }, + + /* IFACETYPE */ + { + DW_TAG_typedef, DW_CHILDREN_yes, + DW_AT_name, DW_FORM_string, + DW_AT_type, DW_FORM_ref_addr, + 0, 0 + }, + + /* MAPTYPE */ + { + DW_TAG_typedef, DW_CHILDREN_no, + DW_AT_name, DW_FORM_string, + DW_AT_type, DW_FORM_ref_addr, + 0, 0 + }, + + /* PTRTYPE */ + { + DW_TAG_pointer_type, DW_CHILDREN_no, + DW_AT_name, DW_FORM_string, + DW_AT_type, DW_FORM_ref_addr, + 0, 0 + }, + + /* SLICETYPE */ + { + DW_TAG_structure_type, DW_CHILDREN_yes, + DW_AT_name, DW_FORM_string, + DW_AT_byte_size, DW_FORM_udata, + 0, 0 + }, + + /* STRINGTYPE */ + { + DW_TAG_structure_type, DW_CHILDREN_yes, + DW_AT_name, DW_FORM_string, + DW_AT_byte_size, DW_FORM_udata, + 0, 0 + }, + + /* STRUCTTYPE */ + { + DW_TAG_structure_type, DW_CHILDREN_yes, + DW_AT_name, DW_FORM_string, + DW_AT_byte_size, DW_FORM_udata, + 0, 0 + }, + + /* TYPEDECL */ + { + DW_TAG_typedef, DW_CHILDREN_no, + DW_AT_name, DW_FORM_string, + DW_AT_type, DW_FORM_ref_addr, + 0, 0 + }, +}; + +static void +writeabbrev(void) +{ + int i, n; + + abbrevo = cpos(); + for (i = 1; i < DW_NABRV; i++) { + // See section 7.5.3 + uleb128put(i); + uleb128put(abbrevs[i].tag); + cput(abbrevs[i].children); + // 0 is not a valid attr or form, and DWAbbrev.attr is + // 0-terminated, so we can treat it as a string + n = strlen((char*)abbrevs[i].attr) / 2; + strnput((char*)abbrevs[i].attr, + (n+1) * sizeof(DWAttrForm)); + } + cput(0); + abbrevsize = cpos() - abbrevo; +} + +/* + * Debugging Information Entries and their attributes. + */ + +enum +{ + HASHSIZE = 107 +}; + +static uint32 +hashstr(char* s) +{ + uint32 h; + + h = 0; + while (*s) + h = h+h+h + *s++; + return h % HASHSIZE; +} + +// For DW_CLS_string and _block, value should contain the length, and +// data the data, for _reference, value is 0 and data is a DWDie* to +// the referenced instance, for all others, value is the whole thing +// and data is null. + +typedef struct DWAttr DWAttr; +struct DWAttr { + DWAttr *link; + uint8 atr; // DW_AT_ + uint8 cls; // DW_CLS_ + vlong value; + char *data; +}; + +typedef struct DWDie DWDie; +struct DWDie { + int abbrev; + DWDie *link; + DWDie *child; + DWAttr *attr; + // offset into .debug_info section, i.e relative to + // infoo. only valid after call to putdie() + vlong offs; + DWDie **hash; // optional index of children by name, enabled by mkindex() + DWDie *hlink; // bucket chain in parent's index +}; + +/* + * Root DIEs for compilation units, types and global variables. + */ + +static DWDie dwroot; +static DWDie dwtypes; +static DWDie dwglobals; + +static DWAttr* +newattr(DWDie *die, uint8 attr, int cls, vlong value, char *data) +{ + DWAttr *a; + + a = mal(sizeof *a); + a->link = die->attr; + die->attr = a; + a->atr = attr; + a->cls = cls; + a->value = value; + a->data = data; + return a; +} + +// Each DIE (except the root ones) has at least 1 attribute: its +// name. getattr moves the desired one to the front so +// frequently searched ones are found faster. +static DWAttr* +getattr(DWDie *die, uint8 attr) +{ + DWAttr *a, *b; + + if (die->attr->atr == attr) + return die->attr; + + a = die->attr; + b = a->link; + while (b != nil) { + if (b->atr == attr) { + a->link = b->link; + b->link = die->attr; + die->attr = b; + return b; + } + a = b; + b = b->link; + } + return nil; +} + +// Every DIE has at least a DW_AT_name attribute (but it will only be +// written out if it is listed in the abbrev). If its parent is +// keeping an index, the new DIE will be inserted there. +static DWDie* +newdie(DWDie *parent, int abbrev, char *name) +{ + DWDie *die; + int h; + + die = mal(sizeof *die); + die->abbrev = abbrev; + die->link = parent->child; + parent->child = die; + + newattr(die, DW_AT_name, DW_CLS_STRING, strlen(name), name); + + if (parent->hash) { + h = hashstr(name); + die->hlink = parent->hash[h]; + parent->hash[h] = die; + } + + return die; +} + +static void +mkindex(DWDie *die) +{ + die->hash = mal(HASHSIZE * sizeof(DWDie*)); +} + +// Find child by AT_name using hashtable if available or linear scan +// if not. +static DWDie* +find(DWDie *die, char* name) +{ + DWDie *a, *b; + int h; + + if (die->hash == nil) { + for (a = die->child; a != nil; a = a->link) + if (strcmp(name, getattr(a, DW_AT_name)->data) == 0) + return a; + return nil; + } + + h = hashstr(name); + a = die->hash[h]; + + if (a == nil) + return nil; + + + if (strcmp(name, getattr(a, DW_AT_name)->data) == 0) + return a; + + // Move found ones to head of the list. + b = a->hlink; + while (b != nil) { + if (strcmp(name, getattr(b, DW_AT_name)->data) == 0) { + a->hlink = b->hlink; + b->hlink = die->hash[h]; + die->hash[h] = b; + return b; + } + a = b; + b = b->hlink; + } + return nil; +} + +static DWDie* +find_or_diag(DWDie *die, char* name) +{ + DWDie *r; + r = find(die, name); + if (r == nil) { + diag("dwarf find: %s has no %s", getattr(die, DW_AT_name)->data, name); + errorexit(); + } + return r; +} + +static DWAttr* +newrefattr(DWDie *die, uint8 attr, DWDie* ref) +{ + if (ref == nil) + return nil; + return newattr(die, attr, DW_CLS_REFERENCE, 0, (char*)ref); +} + +static int fwdcount; + +static void +putattr(int form, int cls, vlong value, char *data) +{ + switch(form) { + case DW_FORM_addr: // address + addrput(value); + break; + + case DW_FORM_block1: // block + value &= 0xff; + cput(value); + while(value--) + cput(*data++); + break; + + case DW_FORM_block2: // block + value &= 0xffff; + WPUT(value); + while(value--) + cput(*data++); + break; + + case DW_FORM_block4: // block + value &= 0xffffffff; + LPUT(value); + while(value--) + cput(*data++); + break; + + case DW_FORM_block: // block + uleb128put(value); + while(value--) + cput(*data++); + break; + + case DW_FORM_data1: // constant + cput(value); + break; + + case DW_FORM_data2: // constant + WPUT(value); + break; + + case DW_FORM_data4: // constant, {line,loclist,mac,rangelist}ptr + LPUT(value); + break; + + case DW_FORM_data8: // constant, {line,loclist,mac,rangelist}ptr + VPUT(value); + break; + + case DW_FORM_sdata: // constant + sleb128put(value); + break; + + case DW_FORM_udata: // constant + uleb128put(value); + break; + + case DW_FORM_string: // string + strnput(data, value+1); + break; + + case DW_FORM_flag: // flag + cput(value?1:0); + break; + + case DW_FORM_ref_addr: // reference to a DIE in the .info section + if (data == nil) { + diag("dwarf: null reference"); + LPUT(0); // invalid dwarf, gdb will complain. + } else { + if (((DWDie*)data)->offs == 0) + fwdcount++; + LPUT(((DWDie*)data)->offs); + } + break; + + case DW_FORM_ref1: // reference within the compilation unit + case DW_FORM_ref2: // reference + case DW_FORM_ref4: // reference + case DW_FORM_ref8: // reference + case DW_FORM_ref_udata: // reference + + case DW_FORM_strp: // string + case DW_FORM_indirect: // (see Section 7.5.3) + default: + diag("dwarf: unsupported attribute form %d / class %d", form, cls); + errorexit(); + } +} + +// Note that we can (and do) add arbitrary attributes to a DIE, but +// only the ones actually listed in the Abbrev will be written out. +static void +putattrs(int abbrev, DWAttr* attr) +{ + DWAttr *attrs[DW_AT_recursive + 1]; + DWAttrForm* af; + + memset(attrs, 0, sizeof attrs); + for( ; attr; attr = attr->link) + if (attr->atr < nelem(attrs)) + attrs[attr->atr] = attr; + + for(af = abbrevs[abbrev].attr; af->attr; af++) + if (attrs[af->attr]) + putattr(af->form, + attrs[af->attr]->cls, + attrs[af->attr]->value, + attrs[af->attr]->data); + else + putattr(af->form, 0, 0, 0); +} + +static void putdie(DWDie* die); + +static void +putdies(DWDie* die) +{ + for(; die; die = die->link) + putdie(die); +} + +static void +putdie(DWDie* die) +{ + die->offs = cpos() - infoo; + uleb128put(die->abbrev); + putattrs(die->abbrev, die->attr); + if (abbrevs[die->abbrev].children) { + putdies(die->child); + cput(0); + } +} + +static void +reverselist(DWDie** list) +{ + DWDie *curr, *prev; + + curr = *list; + prev = nil; + while(curr != nil) { + DWDie* next = curr->link; + curr->link = prev; + prev = curr; + curr = next; + } + *list = prev; +} + +static void +reversetree(DWDie** list) +{ + DWDie *die; + + reverselist(list); + for (die = *list; die != nil; die = die->link) + if (abbrevs[die->abbrev].children) + reversetree(&die->child); +} + +static void +newmemberoffsetattr(DWDie *die, int32 offs) +{ + char block[10]; + int i; + + i = 0; + if (offs != 0) { + block[i++] = DW_OP_consts; + i += sleb128enc(offs, block+i); + block[i++] = DW_OP_plus; + } + newattr(die, DW_AT_data_member_location, DW_CLS_BLOCK, i, mal(i)); + memmove(die->attr->data, block, i); +} + +// GDB doesn't like DW_FORM_addr for DW_AT_location, so emit a +// location expression that evals to a const. +static void +newabslocexprattr(DWDie *die, vlong addr) +{ + char block[10]; + int i; + + i = 0; + block[i++] = DW_OP_constu; + i += uleb128enc(addr, block+i); + newattr(die, DW_AT_location, DW_CLS_BLOCK, i, mal(i)); + memmove(die->attr->data, block, i); +} + +// Decoding the type.* symbols. This has to be in sync with +// ../../pkg/runtime/type.go, or more specificaly, with what +// ../gc/reflect.c stuffs in these. + +enum { + KindBool = 1, + KindInt, + KindInt8, + KindInt16, + KindInt32, + KindInt64, + KindUint, + KindUint8, + KindUint16, + KindUint32, + KindUint64, + KindUintptr, + KindFloat32, + KindFloat64, + KindComplex64, + KindComplex128, + KindArray, + KindChan, + KindFunc, + KindInterface, + KindMap, + KindPtr, + KindSlice, + KindString, + KindStruct, + KindUnsafePointer, + + KindNoPointers = 1<<7, + + // size of Type interface header + CommonType structure. + CommonSize = 2*PtrSize+ 4*PtrSize + 8, +}; + +static Reloc* +decode_reloc(Sym *s, int32 off) +{ + int i; + + for (i = 0; i < s->nr; i++) + if (s->r[i].off == off) + return s->r + i; + return nil; +} + +static Sym* +decode_reloc_sym(Sym *s, int32 off) +{ + Reloc *r; + + r = decode_reloc(s,off); + if (r == nil) + return nil; + return r->sym; +} + +static uvlong +decode_inuxi(uchar* p, int sz) +{ + uint64 v; + uint32 l; + uchar *cast, *inuxi; + int i; + + v = l = 0; + cast = nil; + inuxi = nil; + switch (sz) { + case 2: + cast = (uchar*)&l; + inuxi = inuxi2; + break; + case 4: + cast = (uchar*)&l; + inuxi = inuxi4; + break; + case 8: + cast = (uchar*)&v; + inuxi = inuxi8; + break; + default: + diag("dwarf: decode inuxi %d", sz); + errorexit(); + } + for (i = 0; i < sz; i++) + cast[inuxi[i]] = p[i]; + if (sz == 8) + return v; + return l; +} + +// Type.commonType.kind +static uint8 +decodetype_kind(Sym *s) +{ + return s->p[3*PtrSize + 7] & ~KindNoPointers; // 0x13 / 0x1f +} + +// Type.commonType.size +static vlong +decodetype_size(Sym *s) +{ + return decode_inuxi(s->p + 2*PtrSize, PtrSize); // 0x8 / 0x10 +} + +// Type.ArrayType.elem and Type.SliceType.Elem +static Sym* +decodetype_arrayelem(Sym *s) +{ + return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30 +} + +static vlong +decodetype_arraylen(Sym *s) +{ + return decode_inuxi(s->p + CommonSize+PtrSize, PtrSize); +} + +// Type.PtrType.elem +static Sym* +decodetype_ptrelem(Sym *s) +{ + return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30 +} + +// Type.MapType.key, elem +static Sym* +decodetype_mapkey(Sym *s) +{ + return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30 +} +static Sym* +decodetype_mapvalue(Sym *s) +{ + return decode_reloc_sym(s, CommonSize+PtrSize); // 0x20 / 0x38 +} + +// Type.ChanType.elem +static Sym* +decodetype_chanelem(Sym *s) +{ + return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30 +} + +// Type.FuncType.dotdotdot +static int +decodetype_funcdotdotdot(Sym *s) +{ + return s->p[CommonSize]; +} + +// Type.FuncType.in.len +static int +decodetype_funcincount(Sym *s) +{ + return decode_inuxi(s->p + CommonSize+2*PtrSize, 4); +} + +static int +decodetype_funcoutcount(Sym *s) +{ + return decode_inuxi(s->p + CommonSize+3*PtrSize + 2*4, 4); +} + +static Sym* +decodetype_funcintype(Sym *s, int i) +{ + Reloc *r; + + r = decode_reloc(s, CommonSize + PtrSize); + if (r == nil) + return nil; + return decode_reloc_sym(r->sym, r->add + i * PtrSize); +} + +static Sym* +decodetype_funcouttype(Sym *s, int i) +{ + Reloc *r; + + r = decode_reloc(s, CommonSize + 2*PtrSize + 2*4); + if (r == nil) + return nil; + return decode_reloc_sym(r->sym, r->add + i * PtrSize); +} + +// Type.StructType.fields.Slice::len +static int +decodetype_structfieldcount(Sym *s) +{ + return decode_inuxi(s->p + CommonSize + PtrSize, 4); +} + +enum { + StructFieldSize = 5*PtrSize +}; +// Type.StructType.fields[]-> name, typ and offset. +static char* +decodetype_structfieldname(Sym *s, int i) +{ + Reloc *r; + + // go.string."foo" 0x28 / 0x40 + s = decode_reloc_sym(s, CommonSize + PtrSize + 2*4 + i*StructFieldSize); + if (s == nil) // embedded structs have a nil name. + return nil; + r = decode_reloc(s, 0); // s has a pointer to the string data at offset 0 + if (r == nil) // shouldn't happen. + return nil; + return (char*) r->sym->p + r->add; // the c-string +} + +static Sym* +decodetype_structfieldtype(Sym *s, int i) +{ + return decode_reloc_sym(s, CommonSize + PtrSize + 2*4 + i*StructFieldSize + 2*PtrSize); +} + +static vlong +decodetype_structfieldoffs(Sym *s, int i) +{ + return decode_inuxi(s->p + CommonSize + PtrSize + 2*4 + i*StructFieldSize + 4*PtrSize, 4); +} + +// InterfaceTYpe.methods.len +static vlong +decodetype_ifacemethodcount(Sym *s) +{ + return decode_inuxi(s->p + CommonSize + PtrSize, 4); +} + + +// Fake attributes for slices, maps and channel +enum { + DW_AT_internal_elem_type = 250, // channels and slices + DW_AT_internal_key_type = 251, // maps + DW_AT_internal_val_type = 252, // maps + DW_AT_internal_location = 253, // params and locals +}; + +static DWDie* defptrto(DWDie *dwtype); // below + +// Lookup predefined types +static Sym* +lookup_or_diag(char *n) +{ + Sym *s; + + s = rlookup(n, 0); + if (s == nil || s->size == 0) { + diag("dwarf: missing type: %s", n); + errorexit(); + } + return s; +} + +// Define gotype, for composite ones recurse into constituents. +static DWDie* +defgotype(Sym *gotype) +{ + DWDie *die, *fld; + Sym *s; + char *name, *f; + uint8 kind; + vlong bytesize; + int i, nfields; + + if (gotype == nil) + return find_or_diag(&dwtypes, ""); + + if (strncmp("type.", gotype->name, 5) != 0) { + diag("dwarf: type name doesn't start with \".type\": %s", gotype->name); + return find_or_diag(&dwtypes, ""); + } + name = gotype->name + 5; // could also decode from Type.string + + die = find(&dwtypes, name); + if (die != nil) + return die; + + if (0 && debug['v'] > 2) + print("new type: %Y\n", gotype); + + kind = decodetype_kind(gotype); + bytesize = decodetype_size(gotype); + + switch (kind) { + case KindBool: + die = newdie(&dwtypes, DW_ABRV_BASETYPE, name); + newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_boolean, 0); + newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); + break; + + case KindInt: + case KindInt8: + case KindInt16: + case KindInt32: + case KindInt64: + die = newdie(&dwtypes, DW_ABRV_BASETYPE, name); + newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_signed, 0); + newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); + break; + + case KindUint: + case KindUint8: + case KindUint16: + case KindUint32: + case KindUint64: + case KindUintptr: + die = newdie(&dwtypes, DW_ABRV_BASETYPE, name); + newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_unsigned, 0); + newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); + break; + + case KindFloat32: + case KindFloat64: + die = newdie(&dwtypes, DW_ABRV_BASETYPE, name); + newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_float, 0); + newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); + break; + + case KindComplex64: + case KindComplex128: + die = newdie(&dwtypes, DW_ABRV_BASETYPE, name); + newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_complex_float, 0); + newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); + break; + + case KindArray: + die = newdie(&dwtypes, DW_ABRV_ARRAYTYPE, name); + newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); + s = decodetype_arrayelem(gotype); + newrefattr(die, DW_AT_type, defgotype(s)); + fld = newdie(die, DW_ABRV_ARRAYRANGE, "range"); + newattr(fld, DW_AT_upper_bound, DW_CLS_CONSTANT, decodetype_arraylen(gotype), 0); + newrefattr(fld, DW_AT_type, find_or_diag(&dwtypes, "uintptr")); + break; + + case KindChan: + die = newdie(&dwtypes, DW_ABRV_CHANTYPE, name); + newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); + s = decodetype_chanelem(gotype); + newrefattr(die, DW_AT_internal_elem_type, defgotype(s)); + break; + + case KindFunc: + die = newdie(&dwtypes, DW_ABRV_FUNCTYPE, name); + newrefattr(die, DW_AT_type, find_or_diag(&dwtypes, "void")); + nfields = decodetype_funcincount(gotype); + for (i = 0; i < nfields; i++) { + s = decodetype_funcintype(gotype, i); + fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s->name+5); + newrefattr(fld, DW_AT_type, defgotype(s)); + } + if (decodetype_funcdotdotdot(gotype)) + newdie(die, DW_ABRV_DOTDOTDOT, "..."); + nfields = decodetype_funcoutcount(gotype); + for (i = 0; i < nfields; i++) { + s = decodetype_funcouttype(gotype, i); + fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s->name+5); + newrefattr(fld, DW_AT_type, defptrto(defgotype(s))); + } + break; + + case KindInterface: + die = newdie(&dwtypes, DW_ABRV_IFACETYPE, name); + newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); + nfields = decodetype_ifacemethodcount(gotype); + if (nfields == 0) + s = lookup_or_diag("type.runtime.eface"); + else + s = lookup_or_diag("type.runtime.iface"); + newrefattr(die, DW_AT_type, defgotype(s)); + break; + + case KindMap: + die = newdie(&dwtypes, DW_ABRV_MAPTYPE, name); + s = decodetype_mapkey(gotype); + newrefattr(die, DW_AT_internal_key_type, defgotype(s)); + s = decodetype_mapvalue(gotype); + newrefattr(die, DW_AT_internal_val_type, defgotype(s)); + break; + + case KindPtr: + die = newdie(&dwtypes, DW_ABRV_PTRTYPE, name); + s = decodetype_ptrelem(gotype); + newrefattr(die, DW_AT_type, defgotype(s)); + break; + + case KindSlice: + die = newdie(&dwtypes, DW_ABRV_SLICETYPE, name); + newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); + s = decodetype_arrayelem(gotype); + newrefattr(die, DW_AT_internal_elem_type, defgotype(s)); + break; + + case KindString: + die = newdie(&dwtypes, DW_ABRV_STRINGTYPE, name); + newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); + break; + + case KindStruct: + die = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, name); + newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); + nfields = decodetype_structfieldcount(gotype); + for (i = 0; i < nfields; i++) { + f = decodetype_structfieldname(gotype, i); + s = decodetype_structfieldtype(gotype, i); + if (f == nil) + f = s->name + 5; // skip "type." + fld = newdie(die, DW_ABRV_STRUCTFIELD, f); + newrefattr(fld, DW_AT_type, defgotype(s)); + newmemberoffsetattr(fld, decodetype_structfieldoffs(gotype, i)); + } + break; + + case KindUnsafePointer: + die = newdie(&dwtypes, DW_ABRV_PTRTYPE, name); + newrefattr(die, DW_AT_type, find(&dwtypes, "void")); + break; + + default: + diag("dwarf: definition of unknown kind %d: %s", kind, gotype->name); + die = newdie(&dwtypes, DW_ABRV_TYPEDECL, name); + newrefattr(die, DW_AT_type, find_or_diag(&dwtypes, "")); + } + + return die; +} + +// Find or construct *T given T. +static DWDie* +defptrto(DWDie *dwtype) +{ + char ptrname[1024]; + DWDie *die; + + snprint(ptrname, sizeof ptrname, "*%s", getattr(dwtype, DW_AT_name)->data); + die = find(&dwtypes, ptrname); + if (die == nil) { + die = newdie(&dwtypes, DW_ABRV_PTRTYPE, + strcpy(mal(strlen(ptrname)+1), ptrname)); + newrefattr(die, DW_AT_type, dwtype); + } + return die; +} + +// Copies src's children into dst. Copies attributes by value. +// DWAttr.data is copied as pointer only. +static void +copychildren(DWDie *dst, DWDie *src) +{ + DWDie *c; + DWAttr *a; + + for (src = src->child; src != nil; src = src->link) { + c = newdie(dst, src->abbrev, getattr(src, DW_AT_name)->data); + for (a = src->attr; a != nil; a = a->link) + newattr(c, a->atr, a->cls, a->value, a->data); + copychildren(c, src); + } + reverselist(&dst->child); +} + +// Search children (assumed to have DW_TAG_member) for the one named +// field and set its DW_AT_type to dwtype +static void +substitutetype(DWDie *structdie, char *field, DWDie* dwtype) +{ + DWDie *child; + DWAttr *a; + + child = find_or_diag(structdie, field); + if (child == nil) + return; + + a = getattr(child, DW_AT_type); + if (a != nil) + a->data = (char*) dwtype; + else + newrefattr(child, DW_AT_type, dwtype); +} + +static void +synthesizestringtypes(DWDie* die) +{ + DWDie *prototype; + + prototype = defgotype(lookup_or_diag("type.runtime._string")); + if (prototype == nil) + return; + + for (; die != nil; die = die->link) { + if (die->abbrev != DW_ABRV_STRINGTYPE) + continue; + copychildren(die, prototype); + } +} + +static void +synthesizeslicetypes(DWDie *die) +{ + DWDie *prototype, *elem; + + prototype = defgotype(lookup_or_diag("type.runtime.slice")); + if (prototype == nil) + return; + + for (; die != nil; die = die->link) { + if (die->abbrev != DW_ABRV_SLICETYPE) + continue; + copychildren(die, prototype); + elem = (DWDie*) getattr(die, DW_AT_internal_elem_type)->data; + substitutetype(die, "array", defptrto(elem)); + } +} + +static char* +mkinternaltypename(char *base, char *arg1, char *arg2) +{ + char buf[1024]; + char *n; + + if (arg2 == nil) + snprint(buf, sizeof buf, "%s<%s>", base, arg1); + else + snprint(buf, sizeof buf, "%s<%s,%s>", base, arg1, arg2); + n = mal(strlen(buf) + 1); + memmove(n, buf, strlen(buf)); + return n; +} + + +// synthesizemaptypes is way too closely married to runtime/hashmap.c +enum { + MaxValsize = 256 - 64 +}; + +static void +synthesizemaptypes(DWDie *die) +{ + + DWDie *hash, *hash_subtable, *hash_entry, + *dwh, *dwhs, *dwhe, *dwhash, *keytype, *valtype, *fld; + int hashsize, keysize, valsize, datsize, valsize_in_hash, datavo; + DWAttr *a; + + hash = defgotype(lookup_or_diag("type.runtime.hmap")); + hash_subtable = defgotype(lookup_or_diag("type.runtime.hash_subtable")); + hash_entry = defgotype(lookup_or_diag("type.runtime.hash_entry")); + + if (hash == nil || hash_subtable == nil || hash_entry == nil) + return; + + dwhash = (DWDie*)getattr(find_or_diag(hash_entry, "hash"), DW_AT_type)->data; + if (dwhash == nil) + return; + + hashsize = getattr(dwhash, DW_AT_byte_size)->value; + + for (; die != nil; die = die->link) { + if (die->abbrev != DW_ABRV_MAPTYPE) + continue; + + keytype = (DWDie*) getattr(die, DW_AT_internal_key_type)->data; + valtype = (DWDie*) getattr(die, DW_AT_internal_val_type)->data; + + a = getattr(keytype, DW_AT_byte_size); + keysize = a ? a->value : PtrSize; // We don't store size with Pointers + + a = getattr(valtype, DW_AT_byte_size); + valsize = a ? a->value : PtrSize; + + // This is what happens in hash_init and makemap_c + valsize_in_hash = valsize; + if (valsize > MaxValsize) + valsize_in_hash = PtrSize; + datavo = keysize; + if (valsize_in_hash >= PtrSize) + datavo = rnd(keysize, PtrSize); + datsize = datavo + valsize_in_hash; + if (datsize < PtrSize) + datsize = PtrSize; + datsize = rnd(datsize, PtrSize); + + // Construct struct hash_entry + dwhe = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, + mkinternaltypename("hash_entry", + getattr(keytype, DW_AT_name)->data, + getattr(valtype, DW_AT_name)->data)); + + fld = newdie(dwhe, DW_ABRV_STRUCTFIELD, "hash"); + newrefattr(fld, DW_AT_type, dwhash); + newmemberoffsetattr(fld, 0); + + fld = newdie(dwhe, DW_ABRV_STRUCTFIELD, "key"); + newrefattr(fld, DW_AT_type, keytype); + newmemberoffsetattr(fld, hashsize); + + fld = newdie(dwhe, DW_ABRV_STRUCTFIELD, "val"); + if (valsize > MaxValsize) + valtype = defptrto(valtype); + newrefattr(fld, DW_AT_type, valtype); + newmemberoffsetattr(fld, hashsize + datavo); + newattr(dwhe, DW_AT_byte_size, DW_CLS_CONSTANT, hashsize + datsize, nil); + + // Construct hash_subtable> + dwhs = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, + mkinternaltypename("hash_subtable", + getattr(keytype, DW_AT_name)->data, + getattr(valtype, DW_AT_name)->data)); + copychildren(dwhs, hash_subtable); + substitutetype(dwhs, "last", defptrto(dwhe)); + substitutetype(dwhs, "entry", dwhe); // todo: []hash_entry with dynamic size + newattr(dwhs, DW_AT_byte_size, DW_CLS_CONSTANT, + getattr(hash_subtable, DW_AT_byte_size)->value, nil); + + // Construct hash + dwh = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, + mkinternaltypename("hash", + getattr(keytype, DW_AT_name)->data, + getattr(valtype, DW_AT_name)->data)); + copychildren(dwh, hash); + substitutetype(dwh, "st", defptrto(dwhs)); + newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT, + getattr(hash, DW_AT_byte_size)->value, nil); + + newrefattr(die, DW_AT_type, defptrto(dwh)); + } +} + +static void +synthesizechantypes(DWDie *die) +{ + DWDie *sudog, *waitq, *hchan, + *dws, *dww, *dwh, *elemtype; + DWAttr *a; + int elemsize, sudogsize; + + sudog = defgotype(lookup_or_diag("type.runtime.sudog")); + waitq = defgotype(lookup_or_diag("type.runtime.waitq")); + hchan = defgotype(lookup_or_diag("type.runtime.hchan")); + if (sudog == nil || waitq == nil || hchan == nil) + return; + + sudogsize = getattr(sudog, DW_AT_byte_size)->value; + + for (; die != nil; die = die->link) { + if (die->abbrev != DW_ABRV_CHANTYPE) + continue; + elemtype = (DWDie*) getattr(die, DW_AT_internal_elem_type)->data; + a = getattr(elemtype, DW_AT_byte_size); + elemsize = a ? a->value : PtrSize; + + // sudog + dws = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, + mkinternaltypename("sudog", + getattr(elemtype, DW_AT_name)->data, nil)); + copychildren(dws, sudog); + substitutetype(dws, "elem", elemtype); + newattr(dws, DW_AT_byte_size, DW_CLS_CONSTANT, + sudogsize + (elemsize > 8 ? elemsize - 8 : 0), nil); + + // waitq + dww = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, + mkinternaltypename("waitq", getattr(elemtype, DW_AT_name)->data, nil)); + copychildren(dww, waitq); + substitutetype(dww, "first", defptrto(dws)); + substitutetype(dww, "last", defptrto(dws)); + newattr(dww, DW_AT_byte_size, DW_CLS_CONSTANT, + getattr(waitq, DW_AT_byte_size)->value, nil); + + // hchan + dwh = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, + mkinternaltypename("hchan", getattr(elemtype, DW_AT_name)->data, nil)); + copychildren(dwh, hchan); + substitutetype(dwh, "recvq", dww); + substitutetype(dwh, "sendq", dww); + newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT, + getattr(hchan, DW_AT_byte_size)->value, nil); + + newrefattr(die, DW_AT_type, defptrto(dwh)); + } +} + +// For use with pass.c::genasmsym +static void +defdwsymb(Sym* sym, char *s, int t, vlong v, vlong size, int ver, Sym *gotype) +{ + DWDie *dv, *dt; + + USED(size); + if (strncmp(s, "go.string.", 10) == 0) + return; + + if (strncmp(s, "type.", 5) == 0 && strcmp(s, "type.*") != 0) { + defgotype(sym); + return; + } + + dv = nil; + + switch (t) { + default: + return; + case 'd': + case 'b': + case 'D': + case 'B': + dv = newdie(&dwglobals, DW_ABRV_VARIABLE, s); + newabslocexprattr(dv, v); + if (ver == 0) + newattr(dv, DW_AT_external, DW_CLS_FLAG, 1, 0); + // fallthrough + case 'a': + case 'p': + dt = defgotype(gotype); + } + + if (dv != nil) + newrefattr(dv, DW_AT_type, dt); +} + +// TODO(lvd) For now, just append them all to the first compilation +// unit (that should be main), in the future distribute them to the +// appropriate compilation units. +static void +movetomodule(DWDie *parent) +{ + DWDie *die; + + for (die = dwroot.child->child; die->link != nil; die = die->link) /* nix */; + die->link = parent->child; +} + +/* + * Filename fragments for the line history stack. + */ + +static char **ftab; +static int ftabsize; + +void +dwarfaddfrag(int n, char *frag) +{ + int s; + + if (n >= ftabsize) { + s = ftabsize; + ftabsize = 1 + n + (n >> 2); + ftab = realloc(ftab, ftabsize * sizeof(ftab[0])); + memset(ftab + s, 0, (ftabsize - s) * sizeof(ftab[0])); + } + + if (*frag == '<') + frag++; + ftab[n] = frag; +} + +// Returns a malloc'ed string, piecewise copied from the ftab. +static char * +decodez(char *s) +{ + int len, o; + char *ss, *f; + char *r, *rb, *re; + + len = 0; + ss = s + 1; // first is 0 + while((o = ((uint8)ss[0] << 8) | (uint8)ss[1]) != 0) { + if (o < 0 || o >= ftabsize) { + diag("dwarf: corrupt z entry"); + return 0; + } + f = ftab[o]; + if (f == nil) { + diag("dwarf: corrupt z entry"); + return 0; + } + len += strlen(f) + 1; // for the '/' + ss += 2; + } + + if (len == 0) + return 0; + + r = malloc(len + 1); + rb = r; + re = rb + len + 1; + + s++; + while((o = ((uint8)s[0] << 8) | (uint8)s[1]) != 0) { + f = ftab[o]; + if (rb == r || rb[-1] == '/') + rb = seprint(rb, re, "%s", f); + else + rb = seprint(rb, re, "/%s", f); + s += 2; + } + return r; +} + +/* + * The line history itself + */ + +static char **histfile; // [0] holds "", DW_LNS_set_file arguments must be > 0. +static int histfilesize; +static int histfilecap; + +static void +clearhistfile(void) +{ + int i; + + // [0] holds "" + for (i = 1; i < histfilesize; i++) + free(histfile[i]); + histfilesize = 0; +} + +static int +addhistfile(char *zentry) +{ + char *fname; + + if (histfilesize == histfilecap) { + histfilecap = 2 * histfilecap + 2; + histfile = realloc(histfile, histfilecap * sizeof(char*)); + } + if (histfilesize == 0) + histfile[histfilesize++] = ""; + + fname = decodez(zentry); +// print("addhistfile %d: %s\n", histfilesize, fname); + if (fname == 0) + return -1; + + // Don't fill with duplicates (check only top one). + if (strcmp(fname, histfile[histfilesize-1]) == 0) { + free(fname); + return histfilesize - 1; + } + + histfile[histfilesize++] = fname; + return histfilesize - 1; +} + +// if the histfile stack contains ..../runtime/runtime_defs.go +// use that to set gdbscript +static void +finddebugruntimepath(void) +{ + int i, l; + char *c; + + for (i = 1; i < histfilesize; i++) { + if ((c = strstr(histfile[i], "runtime/runtime_defs.go")) != nil) { + l = c - histfile[i]; + memmove(gdbscript, histfile[i], l); + memmove(gdbscript + l, "runtime/runtime-gdb.py", strlen("runtime/runtime-gdb.py") + 1); + break; + } + } +} + +// Go's runtime C sources are sane, and Go sources nest only 1 level, +// so a handful would be plenty, if it weren't for the fact that line +// directives can push an unlimited number of them. +static struct { + int file; + vlong line; +} *includestack; +static int includestacksize; +static int includetop; +static vlong absline; + +typedef struct Linehist Linehist; +struct Linehist { + Linehist *link; + vlong absline; + vlong line; + int file; +}; + +static Linehist *linehist; + +static void +checknesting(void) +{ + if (includetop < 0) { + diag("dwarf: corrupt z stack"); + errorexit(); + } + if (includetop >= includestacksize) { + includestacksize += 1; + includestacksize <<= 2; +// print("checknesting: growing to %d\n", includestacksize); + includestack = realloc(includestack, includestacksize * sizeof *includestack); + } +} + +/* + * Return false if the a->link chain contains no history, otherwise + * returns true and finds z and Z entries in the Auto list (of a + * Prog), and resets the history stack + */ +static int +inithist(Auto *a) +{ + Linehist *lh; + + for (; a; a = a->link) + if (a->type == D_FILE) + break; + if (a==nil) + return 0; + + // We have a new history. They are guaranteed to come completely + // at the beginning of the compilation unit. + if (a->aoffset != 1) { + diag("dwarf: stray 'z' with offset %d", a->aoffset); + return 0; + } + + // Clear the history. + clearhistfile(); + includetop = 0; + checknesting(); + includestack[includetop].file = 0; + includestack[includetop].line = -1; + absline = 0; + while (linehist != nil) { + lh = linehist->link; + free(linehist); + linehist = lh; + } + + // Construct the new one. + for (; a; a = a->link) { + if (a->type == D_FILE) { // 'z' + int f = addhistfile(a->asym->name); + if (f < 0) { // pop file + includetop--; + checknesting(); + } else { // pushed a file (potentially same) + includestack[includetop].line += a->aoffset - absline; + includetop++; + checknesting(); + includestack[includetop].file = f; + includestack[includetop].line = 1; + } + absline = a->aoffset; + } else if (a->type == D_FILE1) { // 'Z' + // We could just fixup the current + // linehist->line, but there doesn't appear to + // be a guarantee that every 'Z' is preceded + // by its own 'z', so do the safe thing and + // update the stack and push a new Linehist + // entry + includestack[includetop].line = a->aoffset; + } else + continue; + if (linehist == 0 || linehist->absline != absline) { + Linehist* lh = malloc(sizeof *lh); + lh->link = linehist; + lh->absline = absline; + linehist = lh; + } + linehist->file = includestack[includetop].file; + linehist->line = includestack[includetop].line; + } + return 1; +} + +static Linehist * +searchhist(vlong absline) +{ + Linehist *lh; + + for (lh = linehist; lh; lh = lh->link) + if (lh->absline <= absline) + break; + return lh; +} + +static int +guesslang(char *s) +{ + if(strlen(s) >= 3 && strcmp(s+strlen(s)-3, ".go") == 0) + return DW_LANG_Go; + + return DW_LANG_C; +} + +/* + * Generate short opcodes when possible, long ones when neccesary. + * See section 6.2.5 + */ + +enum { + LINE_BASE = -1, + LINE_RANGE = 4, + OPCODE_BASE = 5 +}; + +static void +putpclcdelta(vlong delta_pc, vlong delta_lc) +{ + if (LINE_BASE <= delta_lc && delta_lc < LINE_BASE+LINE_RANGE) { + vlong opcode = OPCODE_BASE + (delta_lc - LINE_BASE) + (LINE_RANGE * delta_pc); + if (OPCODE_BASE <= opcode && opcode < 256) { + cput(opcode); + return; + } + } + + if (delta_pc) { + cput(DW_LNS_advance_pc); + sleb128put(delta_pc); + } + + cput(DW_LNS_advance_line); + sleb128put(delta_lc); + cput(DW_LNS_copy); +} + +static void +newcfaoffsetattr(DWDie *die, int32 offs) +{ + char block[10]; + int i; + + i = 0; + + block[i++] = DW_OP_call_frame_cfa; + if (offs != 0) { + block[i++] = DW_OP_consts; + i += sleb128enc(offs, block+i); + block[i++] = DW_OP_plus; + } + newattr(die, DW_AT_location, DW_CLS_BLOCK, i, mal(i)); + memmove(die->attr->data, block, i); +} + +static char* +mkvarname(char* name, int da) +{ + char buf[1024]; + char *n; + + snprint(buf, sizeof buf, "%s#%d", name, da); + n = mal(strlen(buf) + 1); + memmove(n, buf, strlen(buf)); + return n; +} + +/* + * Walk prog table, emit line program and build DIE tree. + */ + +// flush previous compilation unit. +static void +flushunit(DWDie *dwinfo, vlong pc, vlong unitstart, int32 header_length) +{ + vlong here; + + if (dwinfo != nil && pc != 0) { + newattr(dwinfo, DW_AT_high_pc, DW_CLS_ADDRESS, pc+1, 0); + } + + if (unitstart >= 0) { + cput(0); // start extended opcode + uleb128put(1); + cput(DW_LNE_end_sequence); + + here = cpos(); + cseek(unitstart); + LPUT(here - unitstart - sizeof(int32)); // unit_length + WPUT(3); // dwarf version + LPUT(header_length); // header length starting here + cseek(here); + } +} + +static void +writelines(void) +{ + Prog *q; + Sym *s; + Auto *a; + vlong unitstart, headerend, offs; + vlong pc, epc, lc, llc, lline; + int currfile; + int i, lang, da, dt; + Linehist *lh; + DWDie *dwinfo, *dwfunc, *dwvar, **dws; + DWDie *varhash[HASHSIZE]; + char *n, *nn; + + unitstart = -1; + headerend = -1; + pc = 0; + epc = 0; + lc = 1; + llc = 1; + currfile = -1; + lineo = cpos(); + dwinfo = nil; + + for(cursym = textp; cursym != nil; cursym = cursym->next) { + s = cursym; + if(s->text == P) + continue; + + // Look for history stack. If we find one, + // we're entering a new compilation unit + + if (inithist(s->autom)) { + flushunit(dwinfo, epc, unitstart, headerend - unitstart - 10); + unitstart = cpos(); + + if(debug['v'] > 1) { + print("dwarf writelines found %s\n", histfile[1]); + Linehist* lh; + for (lh = linehist; lh; lh = lh->link) + print("\t%8lld: [%4lld]%s\n", + lh->absline, lh->line, histfile[lh->file]); + } + + lang = guesslang(histfile[1]); + finddebugruntimepath(); + + dwinfo = newdie(&dwroot, DW_ABRV_COMPUNIT, strdup(histfile[1])); + newattr(dwinfo, DW_AT_language, DW_CLS_CONSTANT,lang, 0); + newattr(dwinfo, DW_AT_stmt_list, DW_CLS_PTR, unitstart - lineo, 0); + newattr(dwinfo, DW_AT_low_pc, DW_CLS_ADDRESS, s->text->pc, 0); + + // Write .debug_line Line Number Program Header (sec 6.2.4) + // Fields marked with (*) must be changed for 64-bit dwarf + LPUT(0); // unit_length (*), will be filled in by flushunit. + WPUT(3); // dwarf version (appendix F) + LPUT(0); // header_length (*), filled in by flushunit. + // cpos == unitstart + 4 + 2 + 4 + cput(1); // minimum_instruction_length + cput(1); // default_is_stmt + cput(LINE_BASE); // line_base + cput(LINE_RANGE); // line_range + cput(OPCODE_BASE); // opcode_base (we only use 1..4) + cput(0); // standard_opcode_lengths[1] + cput(1); // standard_opcode_lengths[2] + cput(1); // standard_opcode_lengths[3] + cput(1); // standard_opcode_lengths[4] + cput(0); // include_directories (empty) + + for (i=1; i < histfilesize; i++) { + strnput(histfile[i], strlen(histfile[i]) + 4); + // 4 zeros: the string termination + 3 fields. + } + + cput(0); // terminate file_names. + headerend = cpos(); + + pc = s->text->pc; + epc = pc; + currfile = 1; + lc = 1; + llc = 1; + + cput(0); // start extended opcode + uleb128put(1 + PtrSize); + cput(DW_LNE_set_address); + addrput(pc); + } + if(s->text == nil) + continue; + + if (unitstart < 0) { + diag("dwarf: reachable code before seeing any history: %P", s->text); + continue; + } + + dwfunc = newdie(dwinfo, DW_ABRV_FUNCTION, s->name); + newattr(dwfunc, DW_AT_low_pc, DW_CLS_ADDRESS, s->value, 0); + epc = s->value + s->size; + newattr(dwfunc, DW_AT_high_pc, DW_CLS_ADDRESS, epc, 0); + if (s->version == 0) + newattr(dwfunc, DW_AT_external, DW_CLS_FLAG, 1, 0); + + if(s->text->link == nil) + continue; + + for(q = s->text; q != P; q = q->link) { + lh = searchhist(q->line); + if (lh == nil) { + diag("dwarf: corrupt history or bad absolute line: %P", q); + continue; + } + + if (lh->file < 1) { // 0 is the past-EOF entry. + // diag("instruction with line number past EOF in %s: %P", histfile[1], q); + continue; + } + + lline = lh->line + q->line - lh->absline; + if (debug['v'] > 1) + print("%6llux %s[%lld] %P\n", (vlong)q->pc, histfile[lh->file], lline, q); + + if (q->line == lc) + continue; + if (currfile != lh->file) { + currfile = lh->file; + cput(DW_LNS_set_file); + uleb128put(currfile); + } + putpclcdelta(q->pc - pc, lline - llc); + pc = q->pc; + lc = q->line; + llc = lline; + } + + da = 0; + dwfunc->hash = varhash; // enable indexing of children by name + memset(varhash, 0, sizeof varhash); + for(a = s->autom; a; a = a->link) { + switch (a->type) { + case D_AUTO: + dt = DW_ABRV_AUTO; + offs = a->aoffset - PtrSize; + break; + case D_PARAM: + dt = DW_ABRV_PARAM; + offs = a->aoffset; + break; + default: + continue; + } + if (strstr(a->asym->name, ".autotmp_")) + continue; + if (find(dwfunc, a->asym->name) != nil) + n = mkvarname(a->asym->name, da); + else + n = a->asym->name; + // Drop the package prefix from locals and arguments. + nn = strrchr(n, '.'); + if (nn) + n = nn + 1; + + dwvar = newdie(dwfunc, dt, n); + newcfaoffsetattr(dwvar, offs); + newrefattr(dwvar, DW_AT_type, defgotype(a->gotype)); + + // push dwvar down dwfunc->child to preserve order + newattr(dwvar, DW_AT_internal_location, DW_CLS_CONSTANT, offs, nil); + dwfunc->child = dwvar->link; // take dwvar out from the top of the list + for (dws = &dwfunc->child; *dws != nil; dws = &(*dws)->link) + if (offs > getattr(*dws, DW_AT_internal_location)->value) + break; + dwvar->link = *dws; + *dws = dwvar; + + da++; + } + + dwfunc->hash = nil; + } + + flushunit(dwinfo, epc, unitstart, headerend - unitstart - 10); + linesize = cpos() - lineo; +} + +/* + * Emit .debug_frame + */ +enum +{ + CIERESERVE = 16, + DATAALIGNMENTFACTOR = -4, // TODO -PtrSize? + FAKERETURNCOLUMN = 16 // TODO gdb6 doesnt like > 15? +}; + +static void +putpccfadelta(vlong deltapc, vlong cfa) +{ + if (deltapc < 0x40) { + cput(DW_CFA_advance_loc + deltapc); + } else if (deltapc < 0x100) { + cput(DW_CFA_advance_loc1); + cput(deltapc); + } else if (deltapc < 0x10000) { + cput(DW_CFA_advance_loc2); + WPUT(deltapc); + } else { + cput(DW_CFA_advance_loc4); + LPUT(deltapc); + } + + cput(DW_CFA_def_cfa_offset_sf); + sleb128put(cfa / DATAALIGNMENTFACTOR); +} + +static void +writeframes(void) +{ + Prog *p, *q; + Sym *s; + vlong fdeo, fdesize, pad, cfa, pc; + + frameo = cpos(); + + // Emit the CIE, Section 6.4.1 + LPUT(CIERESERVE); // initial length, must be multiple of PtrSize + LPUT(0xffffffff); // cid. + cput(3); // dwarf version (appendix F) + cput(0); // augmentation "" + uleb128put(1); // code_alignment_factor + sleb128put(DATAALIGNMENTFACTOR); // guess + uleb128put(FAKERETURNCOLUMN); // return_address_register + + cput(DW_CFA_def_cfa); + uleb128put(DWARFREGSP); // register SP (**ABI-dependent, defined in l.h) + uleb128put(PtrSize); // offset + + cput(DW_CFA_offset + FAKERETURNCOLUMN); // return address + uleb128put(-PtrSize / DATAALIGNMENTFACTOR); // at cfa - x*4 + + // 4 is to exclude the length field. + pad = CIERESERVE + frameo + 4 - cpos(); + if (pad < 0) { + diag("dwarf: CIERESERVE too small by %lld bytes.", -pad); + errorexit(); + } + strnput("", pad); + + for(cursym = textp; cursym != nil; cursym = cursym->next) { + s = cursym; + if(s->text == nil) + continue; + + fdeo = cpos(); + // Emit a FDE, Section 6.4.1, starting wit a placeholder. + LPUT(0); // length, must be multiple of PtrSize + LPUT(0); // Pointer to the CIE above, at offset 0 + addrput(0); // initial location + addrput(0); // address range + + cfa = PtrSize; // CFA starts at sp+PtrSize + p = s->text; + pc = p->pc; + + for(q = p; q->link != P; q = q->link) { + if (q->spadj == 0) + continue; + cfa += q->spadj; + putpccfadelta(q->link->pc - pc, cfa); + pc = q->link->pc; + } + + fdesize = cpos() - fdeo - 4; // exclude the length field. + pad = rnd(fdesize, PtrSize) - fdesize; + strnput("", pad); + fdesize += pad; + + // Emit the FDE header for real, Section 6.4.1. + cseek(fdeo); + LPUT(fdesize); + LPUT(0); + addrput(p->pc); + addrput(s->size); + cseek(fdeo + 4 + fdesize); + } + + cflush(); + framesize = cpos() - frameo; +} + +/* + * Walk DWarfDebugInfoEntries, and emit .debug_info + */ +enum +{ + COMPUNITHEADERSIZE = 4+2+4+1 +}; + +static void +writeinfo(void) +{ + DWDie *compunit; + vlong unitstart, here; + + fwdcount = 0; + + for (compunit = dwroot.child; compunit; compunit = compunit->link) { + unitstart = cpos(); + + // Write .debug_info Compilation Unit Header (sec 7.5.1) + // Fields marked with (*) must be changed for 64-bit dwarf + // This must match COMPUNITHEADERSIZE above. + LPUT(0); // unit_length (*), will be filled in later. + WPUT(3); // dwarf version (appendix F) + LPUT(0); // debug_abbrev_offset (*) + cput(PtrSize); // address_size + + putdie(compunit); + + here = cpos(); + cseek(unitstart); + LPUT(here - unitstart - 4); // exclude the length field. + cseek(here); + } + cflush(); +} + +/* + * Emit .debug_pubnames/_types. _info must have been written before, + * because we need die->offs and infoo/infosize; + */ +static int +ispubname(DWDie *die) { + DWAttr *a; + + switch(die->abbrev) { + case DW_ABRV_FUNCTION: + case DW_ABRV_VARIABLE: + a = getattr(die, DW_AT_external); + return a && a->value; + } + return 0; +} + +static int +ispubtype(DWDie *die) { + return die->abbrev >= DW_ABRV_NULLTYPE; +} + +static vlong +writepub(int (*ispub)(DWDie*)) +{ + DWDie *compunit, *die; + DWAttr *dwa; + vlong unitstart, unitend, sectionstart, here; + + sectionstart = cpos(); + + for (compunit = dwroot.child; compunit != nil; compunit = compunit->link) { + unitstart = compunit->offs - COMPUNITHEADERSIZE; + if (compunit->link != nil) + unitend = compunit->link->offs - COMPUNITHEADERSIZE; + else + unitend = infoo + infosize; + + // Write .debug_pubnames/types Header (sec 6.1.1) + LPUT(0); // unit_length (*), will be filled in later. + WPUT(2); // dwarf version (appendix F) + LPUT(unitstart); // debug_info_offset (of the Comp unit Header) + LPUT(unitend - unitstart); // debug_info_length + + for (die = compunit->child; die != nil; die = die->link) { + if (!ispub(die)) continue; + LPUT(die->offs - unitstart); + dwa = getattr(die, DW_AT_name); + strnput(dwa->data, dwa->value + 1); + } + LPUT(0); + + here = cpos(); + cseek(sectionstart); + LPUT(here - sectionstart - 4); // exclude the length field. + cseek(here); + + } + + return sectionstart; +} + +/* + * emit .debug_aranges. _info must have been written before, + * because we need die->offs of dw_globals. + */ +static vlong +writearanges(void) +{ + DWDie *compunit; + DWAttr *b, *e; + int headersize; + vlong sectionstart; + + sectionstart = cpos(); + headersize = rnd(4+2+4+1+1, PtrSize); // don't count unit_length field itself + + for (compunit = dwroot.child; compunit != nil; compunit = compunit->link) { + b = getattr(compunit, DW_AT_low_pc); + if (b == nil) + continue; + e = getattr(compunit, DW_AT_high_pc); + if (e == nil) + continue; + + // Write .debug_aranges Header + entry (sec 6.1.2) + LPUT(headersize + 4*PtrSize - 4); // unit_length (*) + WPUT(2); // dwarf version (appendix F) + LPUT(compunit->offs - COMPUNITHEADERSIZE); // debug_info_offset + cput(PtrSize); // address_size + cput(0); // segment_size + strnput("", headersize - (4+2+4+1+1)); // align to PtrSize + + addrput(b->value); + addrput(e->value - b->value); + addrput(0); + addrput(0); + } + cflush(); + return sectionstart; +} + +static vlong +writegdbscript(void) +{ + vlong sectionstart; + + sectionstart = cpos(); + + if (gdbscript[0]) { + cput(1); // magic 1 byte? + strnput(gdbscript, strlen(gdbscript)+1); + cflush(); + } + return sectionstart; +} + +static void +align(vlong size) +{ + if(HEADTYPE == Hwindows) // Only Windows PE need section align. + strnput("", rnd(size, PEFILEALIGN) - size); +} + +/* + * This is the main entry point for generating dwarf. After emitting + * the mandatory debug_abbrev section, it calls writelines() to set up + * the per-compilation unit part of the DIE tree, while simultaneously + * emitting the debug_line section. When the final tree contains + * forward references, it will write the debug_info section in 2 + * passes. + * + */ +void +dwarfemitdebugsections(void) +{ + vlong infoe; + DWDie* die; + + if(debug['w']) // disable dwarf + return; + + // For diagnostic messages. + newattr(&dwtypes, DW_AT_name, DW_CLS_STRING, strlen("dwtypes"), "dwtypes"); + + mkindex(&dwroot); + mkindex(&dwtypes); + mkindex(&dwglobals); + + // Some types that must exist to define other ones. + newdie(&dwtypes, DW_ABRV_NULLTYPE, ""); + newdie(&dwtypes, DW_ABRV_NULLTYPE, "void"); + newrefattr(newdie(&dwtypes, DW_ABRV_PTRTYPE, "unsafe.Pointer"), + DW_AT_type, find(&dwtypes, "void")); + die = newdie(&dwtypes, DW_ABRV_BASETYPE, "uintptr"); // needed for array size + newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_unsigned, 0); + newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, PtrSize, 0); + + // Needed by the prettyprinter code for interface inspection. + defgotype(lookup_or_diag("type.runtime.commonType")); + defgotype(lookup_or_diag("type.runtime.InterfaceType")); + defgotype(lookup_or_diag("type.runtime.itab")); + + genasmsym(defdwsymb); + + writeabbrev(); + align(abbrevsize); + writelines(); + align(linesize); + writeframes(); + align(framesize); + + synthesizestringtypes(dwtypes.child); + synthesizeslicetypes(dwtypes.child); + synthesizemaptypes(dwtypes.child); + synthesizechantypes(dwtypes.child); + + reversetree(&dwroot.child); + reversetree(&dwtypes.child); + reversetree(&dwglobals.child); + + movetomodule(&dwtypes); + movetomodule(&dwglobals); + + infoo = cpos(); + writeinfo(); + infoe = cpos(); + pubnameso = infoe; + pubtypeso = infoe; + arangeso = infoe; + gdbscripto = infoe; + + if (fwdcount > 0) { + if (debug['v']) + Bprint(&bso, "%5.2f dwarf pass 2.\n", cputime()); + cseek(infoo); + writeinfo(); + if (fwdcount > 0) { + diag("dwarf: unresolved references after first dwarf info pass"); + errorexit(); + } + if (infoe != cpos()) { + diag("dwarf: inconsistent second dwarf info pass"); + errorexit(); + } + } + infosize = infoe - infoo; + align(infosize); + + pubnameso = writepub(ispubname); + pubnamessize = cpos() - pubnameso; + align(pubnamessize); + + pubtypeso = writepub(ispubtype); + pubtypessize = cpos() - pubtypeso; + align(pubtypessize); + + arangeso = writearanges(); + arangessize = cpos() - arangeso; + align(arangessize); + + gdbscripto = writegdbscript(); + gdbscriptsize = cpos() - gdbscripto; + align(gdbscriptsize); +} + +/* + * Elf. + */ +enum +{ + ElfStrDebugAbbrev, + ElfStrDebugAranges, + ElfStrDebugFrame, + ElfStrDebugInfo, + ElfStrDebugLine, + ElfStrDebugLoc, + ElfStrDebugMacinfo, + ElfStrDebugPubNames, + ElfStrDebugPubTypes, + ElfStrDebugRanges, + ElfStrDebugStr, + ElfStrGDBScripts, + NElfStrDbg +}; + +vlong elfstrdbg[NElfStrDbg]; + +void +dwarfaddshstrings(Sym *shstrtab) +{ + if(debug['w']) // disable dwarf + return; + + elfstrdbg[ElfStrDebugAbbrev] = addstring(shstrtab, ".debug_abbrev"); + elfstrdbg[ElfStrDebugAranges] = addstring(shstrtab, ".debug_aranges"); + elfstrdbg[ElfStrDebugFrame] = addstring(shstrtab, ".debug_frame"); + elfstrdbg[ElfStrDebugInfo] = addstring(shstrtab, ".debug_info"); + elfstrdbg[ElfStrDebugLine] = addstring(shstrtab, ".debug_line"); + elfstrdbg[ElfStrDebugLoc] = addstring(shstrtab, ".debug_loc"); + elfstrdbg[ElfStrDebugMacinfo] = addstring(shstrtab, ".debug_macinfo"); + elfstrdbg[ElfStrDebugPubNames] = addstring(shstrtab, ".debug_pubnames"); + elfstrdbg[ElfStrDebugPubTypes] = addstring(shstrtab, ".debug_pubtypes"); + elfstrdbg[ElfStrDebugRanges] = addstring(shstrtab, ".debug_ranges"); + elfstrdbg[ElfStrDebugStr] = addstring(shstrtab, ".debug_str"); + elfstrdbg[ElfStrGDBScripts] = addstring(shstrtab, ".debug_gdb_scripts"); +} + +void +dwarfaddelfheaders(void) +{ + ElfShdr *sh; + + if(debug['w']) // disable dwarf + return; + + sh = newElfShdr(elfstrdbg[ElfStrDebugAbbrev]); + sh->type = SHT_PROGBITS; + sh->off = abbrevo; + sh->size = abbrevsize; + sh->addralign = 1; + + sh = newElfShdr(elfstrdbg[ElfStrDebugLine]); + sh->type = SHT_PROGBITS; + sh->off = lineo; + sh->size = linesize; + sh->addralign = 1; + + sh = newElfShdr(elfstrdbg[ElfStrDebugFrame]); + sh->type = SHT_PROGBITS; + sh->off = frameo; + sh->size = framesize; + sh->addralign = 1; + + sh = newElfShdr(elfstrdbg[ElfStrDebugInfo]); + sh->type = SHT_PROGBITS; + sh->off = infoo; + sh->size = infosize; + sh->addralign = 1; + + if (pubnamessize > 0) { + sh = newElfShdr(elfstrdbg[ElfStrDebugPubNames]); + sh->type = SHT_PROGBITS; + sh->off = pubnameso; + sh->size = pubnamessize; + sh->addralign = 1; + } + + if (pubtypessize > 0) { + sh = newElfShdr(elfstrdbg[ElfStrDebugPubTypes]); + sh->type = SHT_PROGBITS; + sh->off = pubtypeso; + sh->size = pubtypessize; + sh->addralign = 1; + } + + if (arangessize) { + sh = newElfShdr(elfstrdbg[ElfStrDebugAranges]); + sh->type = SHT_PROGBITS; + sh->off = arangeso; + sh->size = arangessize; + sh->addralign = 1; + } + + if (gdbscriptsize) { + sh = newElfShdr(elfstrdbg[ElfStrGDBScripts]); + sh->type = SHT_PROGBITS; + sh->off = gdbscripto; + sh->size = gdbscriptsize; + sh->addralign = 1; + } +} + +/* + * Macho + */ +void +dwarfaddmachoheaders(void) +{ + MachoSect *msect; + MachoSeg *ms; + vlong fakestart; + int nsect; + + if(debug['w']) // disable dwarf + return; + + // Zero vsize segments won't be loaded in memory, even so they + // have to be page aligned in the file. + fakestart = abbrevo & ~0xfff; + + nsect = 4; + if (pubnamessize > 0) + nsect++; + if (pubtypessize > 0) + nsect++; + if (arangessize > 0) + nsect++; + if (gdbscriptsize > 0) + nsect++; + + ms = newMachoSeg("__DWARF", nsect); + ms->fileoffset = fakestart; + ms->filesize = abbrevo-fakestart; + + msect = newMachoSect(ms, "__debug_abbrev"); + msect->off = abbrevo; + msect->size = abbrevsize; + ms->filesize += msect->size; + + msect = newMachoSect(ms, "__debug_line"); + msect->off = lineo; + msect->size = linesize; + ms->filesize += msect->size; + + msect = newMachoSect(ms, "__debug_frame"); + msect->off = frameo; + msect->size = framesize; + ms->filesize += msect->size; + + msect = newMachoSect(ms, "__debug_info"); + msect->off = infoo; + msect->size = infosize; + ms->filesize += msect->size; + + if (pubnamessize > 0) { + msect = newMachoSect(ms, "__debug_pubnames"); + msect->off = pubnameso; + msect->size = pubnamessize; + ms->filesize += msect->size; + } + + if (pubtypessize > 0) { + msect = newMachoSect(ms, "__debug_pubtypes"); + msect->off = pubtypeso; + msect->size = pubtypessize; + ms->filesize += msect->size; + } + + if (arangessize > 0) { + msect = newMachoSect(ms, "__debug_aranges"); + msect->off = arangeso; + msect->size = arangessize; + ms->filesize += msect->size; + } + + // TODO(lvd) fix gdb/python to load MachO (16 char section name limit) + if (gdbscriptsize > 0) { + msect = newMachoSect(ms, "__debug_gdb_scripts"); + msect->off = gdbscripto; + msect->size = gdbscriptsize; + ms->filesize += msect->size; + } +} + +/* + * Windows PE + */ +void +dwarfaddpeheaders(void) +{ + if(debug['w']) // disable dwarf + return; + + newPEDWARFSection(".debug_abbrev", abbrevsize); + newPEDWARFSection(".debug_line", linesize); + newPEDWARFSection(".debug_frame", framesize); + newPEDWARFSection(".debug_info", infosize); + newPEDWARFSection(".debug_pubnames", pubnamessize); + newPEDWARFSection(".debug_pubtypes", pubtypessize); + newPEDWARFSection(".debug_aranges", arangessize); + newPEDWARFSection(".debug_gdb_scripts", gdbscriptsize); +} diff -r d8d00747375b sys/src/cmd/ld/dwarf.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/src/cmd/ld/dwarf.h Mon Nov 14 17:35:25 2011 +0100 @@ -0,0 +1,30 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* + * Register 'f' symbol file fragments. Doing this while parsing the + * .6 input saves a pass over the symbol table later. + */ +void dwarfaddfrag(int n, char* frag); + +/* + * Emit debug_abbrevs, debug_info and debug_line sections to current + * offset in cout. + */ +void dwarfemitdebugsections(void); + +/* + * Add the dwarf section names to the ELF + * s[ection]h[eader]str[ing]tab. Prerequisite for + * dwarfaddelfheaders(). + */ +void dwarfaddshstrings(Sym *shstrtab); + +/* + * Add section headers pointing to the sections emitted in + * dwarfemitdebugsections. + */ +void dwarfaddelfheaders(void); +void dwarfaddmachoheaders(void); +void dwarfaddpeheaders(void); diff -r d8d00747375b sys/src/cmd/ld/dwarf_defs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/src/cmd/ld/dwarf_defs.h Mon Nov 14 17:35:25 2011 +0100 @@ -0,0 +1,503 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Cut, pasted, tr-and-awk'ed from tables in +// http://dwarfstd.org/doc/Dwarf3.pdf + +// Table 18 +enum +{ + DW_TAG_array_type = 0x01, + DW_TAG_class_type = 0x02, + DW_TAG_entry_point = 0x03, + DW_TAG_enumeration_type = 0x04, + DW_TAG_formal_parameter = 0x05, + DW_TAG_imported_declaration = 0x08, + DW_TAG_label = 0x0a, + DW_TAG_lexical_block = 0x0b, + DW_TAG_member = 0x0d, + DW_TAG_pointer_type = 0x0f, + DW_TAG_reference_type = 0x10, + DW_TAG_compile_unit = 0x11, + DW_TAG_string_type = 0x12, + DW_TAG_structure_type = 0x13, + DW_TAG_subroutine_type = 0x15, + DW_TAG_typedef = 0x16, + DW_TAG_union_type = 0x17, + DW_TAG_unspecified_parameters = 0x18, + DW_TAG_variant = 0x19, + DW_TAG_common_block = 0x1a, + DW_TAG_common_inclusion = 0x1b, + DW_TAG_inheritance = 0x1c, + DW_TAG_inlined_subroutine = 0x1d, + DW_TAG_module = 0x1e, + DW_TAG_ptr_to_member_type = 0x1f, + DW_TAG_set_type = 0x20, + DW_TAG_subrange_type = 0x21, + DW_TAG_with_stmt = 0x22, + DW_TAG_access_declaration = 0x23, + DW_TAG_base_type = 0x24, + DW_TAG_catch_block = 0x25, + DW_TAG_const_type = 0x26, + DW_TAG_constant = 0x27, + DW_TAG_enumerator = 0x28, + DW_TAG_file_type = 0x29, + DW_TAG_friend = 0x2a, + DW_TAG_namelist = 0x2b, + DW_TAG_namelist_item = 0x2c, + DW_TAG_packed_type = 0x2d, + DW_TAG_subprogram = 0x2e, + DW_TAG_template_type_parameter = 0x2f, + DW_TAG_template_value_parameter = 0x30, + DW_TAG_thrown_type = 0x31, + DW_TAG_try_block = 0x32, + DW_TAG_variant_part = 0x33, + DW_TAG_variable = 0x34, + DW_TAG_volatile_type = 0x35, + // Dwarf3 + DW_TAG_dwarf_procedure = 0x36, + DW_TAG_restrict_type = 0x37, + DW_TAG_interface_type = 0x38, + DW_TAG_namespace = 0x39, + DW_TAG_imported_module = 0x3a, + DW_TAG_unspecified_type = 0x3b, + DW_TAG_partial_unit = 0x3c, + DW_TAG_imported_unit = 0x3d, + DW_TAG_condition = 0x3f, + DW_TAG_shared_type = 0x40, + // Dwarf4 + DW_TAG_type_unit = 0x41, + DW_TAG_rvalue_reference_type = 0x42, + DW_TAG_template_alias = 0x43, + + // User defined + DW_TAG_lo_user = 0x4080, + DW_TAG_hi_user = 0xffff, + +}; + +// Table 19 +enum +{ + DW_CHILDREN_no = 0x00, + DW_CHILDREN_yes = 0x01, +}; + +// Not from the spec, but logicaly belongs here +enum +{ + DW_CLS_ADDRESS = 0x01, + DW_CLS_BLOCK, + DW_CLS_CONSTANT, + DW_CLS_FLAG, + DW_CLS_PTR, // lineptr, loclistptr, macptr, rangelistptr + DW_CLS_REFERENCE, + DW_CLS_STRING +}; + +// Table 20 +enum +{ + DW_AT_sibling = 0x01, // reference + DW_AT_location = 0x02, // block, loclistptr + DW_AT_name = 0x03, // string + DW_AT_ordering = 0x09, // constant + DW_AT_byte_size = 0x0b, // block, constant, reference + DW_AT_bit_offset = 0x0c, // block, constant, reference + DW_AT_bit_size = 0x0d, // block, constant, reference + DW_AT_stmt_list = 0x10, // lineptr + DW_AT_low_pc = 0x11, // address + DW_AT_high_pc = 0x12, // address + DW_AT_language = 0x13, // constant + DW_AT_discr = 0x15, // reference + DW_AT_discr_value = 0x16, // constant + DW_AT_visibility = 0x17, // constant + DW_AT_import = 0x18, // reference + DW_AT_string_length = 0x19, // block, loclistptr + DW_AT_common_reference = 0x1a, // reference + DW_AT_comp_dir = 0x1b, // string + DW_AT_const_value = 0x1c, // block, constant, string + DW_AT_containing_type = 0x1d, // reference + DW_AT_default_value = 0x1e, // reference + DW_AT_inline = 0x20, // constant + DW_AT_is_optional = 0x21, // flag + DW_AT_lower_bound = 0x22, // block, constant, reference + DW_AT_producer = 0x25, // string + DW_AT_prototyped = 0x27, // flag + DW_AT_return_addr = 0x2a, // block, loclistptr + DW_AT_start_scope = 0x2c, // constant + DW_AT_bit_stride = 0x2e, // constant + DW_AT_upper_bound = 0x2f, // block, constant, reference + DW_AT_abstract_origin = 0x31, // reference + DW_AT_accessibility = 0x32, // constant + DW_AT_address_class = 0x33, // constant + DW_AT_artificial = 0x34, // flag + DW_AT_base_types = 0x35, // reference + DW_AT_calling_convention = 0x36, // constant + DW_AT_count = 0x37, // block, constant, reference + DW_AT_data_member_location = 0x38, // block, constant, loclistptr + DW_AT_decl_column = 0x39, // constant + DW_AT_decl_file = 0x3a, // constant + DW_AT_decl_line = 0x3b, // constant + DW_AT_declaration = 0x3c, // flag + DW_AT_discr_list = 0x3d, // block + DW_AT_encoding = 0x3e, // constant + DW_AT_external = 0x3f, // flag + DW_AT_frame_base = 0x40, // block, loclistptr + DW_AT_friend = 0x41, // reference + DW_AT_identifier_case = 0x42, // constant + DW_AT_macro_info = 0x43, // macptr + DW_AT_namelist_item = 0x44, // block + DW_AT_priority = 0x45, // reference + DW_AT_segment = 0x46, // block, loclistptr + DW_AT_specification = 0x47, // reference + DW_AT_static_link = 0x48, // block, loclistptr + DW_AT_type = 0x49, // reference + DW_AT_use_location = 0x4a, // block, loclistptr + DW_AT_variable_parameter = 0x4b, // flag + DW_AT_virtuality = 0x4c, // constant + DW_AT_vtable_elem_location = 0x4d, // block, loclistptr + // Dwarf3 + DW_AT_allocated = 0x4e, // block, constant, reference + DW_AT_associated = 0x4f, // block, constant, reference + DW_AT_data_location = 0x50, // block + DW_AT_byte_stride = 0x51, // block, constant, reference + DW_AT_entry_pc = 0x52, // address + DW_AT_use_UTF8 = 0x53, // flag + DW_AT_extension = 0x54, // reference + DW_AT_ranges = 0x55, // rangelistptr + DW_AT_trampoline = 0x56, // address, flag, reference, string + DW_AT_call_column = 0x57, // constant + DW_AT_call_file = 0x58, // constant + DW_AT_call_line = 0x59, // constant + DW_AT_description = 0x5a, // string + DW_AT_binary_scale = 0x5b, // constant + DW_AT_decimal_scale = 0x5c, // constant + DW_AT_small = 0x5d, // reference + DW_AT_decimal_sign = 0x5e, // constant + DW_AT_digit_count = 0x5f, // constant + DW_AT_picture_string = 0x60, // string + DW_AT_mutable = 0x61, // flag + DW_AT_threads_scaled = 0x62, // flag + DW_AT_explicit = 0x63, // flag + DW_AT_object_pointer = 0x64, // reference + DW_AT_endianity = 0x65, // constant + DW_AT_elemental = 0x66, // flag + DW_AT_pure = 0x67, // flag + DW_AT_recursive = 0x68, // flag + + DW_AT_lo_user = 0x2000, // --- + DW_AT_hi_user = 0x3fff, // --- + +}; + +// Table 21 +enum +{ + DW_FORM_addr = 0x01, // address + DW_FORM_block2 = 0x03, // block + DW_FORM_block4 = 0x04, // block + DW_FORM_data2 = 0x05, // constant + DW_FORM_data4 = 0x06, // constant, lineptr, loclistptr, macptr, rangelistptr + DW_FORM_data8 = 0x07, // constant, lineptr, loclistptr, macptr, rangelistptr + DW_FORM_string = 0x08, // string + DW_FORM_block = 0x09, // block + DW_FORM_block1 = 0x0a, // block + DW_FORM_data1 = 0x0b, // constant + DW_FORM_flag = 0x0c, // flag + DW_FORM_sdata = 0x0d, // constant + DW_FORM_strp = 0x0e, // string + DW_FORM_udata = 0x0f, // constant + DW_FORM_ref_addr = 0x10, // reference + DW_FORM_ref1 = 0x11, // reference + DW_FORM_ref2 = 0x12, // reference + DW_FORM_ref4 = 0x13, // reference + DW_FORM_ref8 = 0x14, // reference + DW_FORM_ref_udata = 0x15, // reference + DW_FORM_indirect = 0x16, // (see Section 7.5.3) +}; + +// Table 24 (#operands, notes) +enum +{ + DW_OP_addr = 0x03, // 1 constant address (size target specific) + DW_OP_deref = 0x06, // 0 + DW_OP_const1u = 0x08, // 1 1-byte constant + DW_OP_const1s = 0x09, // 1 1-byte constant + DW_OP_const2u = 0x0a, // 1 2-byte constant + DW_OP_const2s = 0x0b, // 1 2-byte constant + DW_OP_const4u = 0x0c, // 1 4-byte constant + DW_OP_const4s = 0x0d, // 1 4-byte constant + DW_OP_const8u = 0x0e, // 1 8-byte constant + DW_OP_const8s = 0x0f, // 1 8-byte constant + DW_OP_constu = 0x10, // 1 ULEB128 constant + DW_OP_consts = 0x11, // 1 SLEB128 constant + DW_OP_dup = 0x12, // 0 + DW_OP_drop = 0x13, // 0 + DW_OP_over = 0x14, // 0 + DW_OP_pick = 0x15, // 1 1-byte stack index + DW_OP_swap = 0x16, // 0 + DW_OP_rot = 0x17, // 0 + DW_OP_xderef = 0x18, // 0 + DW_OP_abs = 0x19, // 0 + DW_OP_and = 0x1a, // 0 + DW_OP_div = 0x1b, // 0 + DW_OP_minus = 0x1c, // 0 + DW_OP_mod = 0x1d, // 0 + DW_OP_mul = 0x1e, // 0 + DW_OP_neg = 0x1f, // 0 + DW_OP_not = 0x20, // 0 + DW_OP_or = 0x21, // 0 + DW_OP_plus = 0x22, // 0 + DW_OP_plus_uconst = 0x23, // 1 ULEB128 addend + DW_OP_shl = 0x24, // 0 + DW_OP_shr = 0x25, // 0 + DW_OP_shra = 0x26, // 0 + DW_OP_xor = 0x27, // 0 + DW_OP_skip = 0x2f, // 1 signed 2-byte constant + DW_OP_bra = 0x28, // 1 signed 2-byte constant + DW_OP_eq = 0x29, // 0 + DW_OP_ge = 0x2a, // 0 + DW_OP_gt = 0x2b, // 0 + DW_OP_le = 0x2c, // 0 + DW_OP_lt = 0x2d, // 0 + DW_OP_ne = 0x2e, // 0 + DW_OP_lit0 = 0x30, // 0 ... + DW_OP_lit31 = 0x4f, // 0 literals 0..31 = (DW_OP_lit0 + + // literal) + DW_OP_reg0 = 0x50, // 0 .. + DW_OP_reg31 = 0x6f, // 0 reg 0..31 = (DW_OP_reg0 + regnum) + DW_OP_breg0 = 0x70, // 1 ... + DW_OP_breg31 = 0x8f, // 1 SLEB128 offset base register 0..31 = (DW_OP_breg0 + regnum) + DW_OP_regx = 0x90, // 1 ULEB128 register + DW_OP_fbreg = 0x91, // 1 SLEB128 offset + DW_OP_bregx = 0x92, // 2 ULEB128 register followed by SLEB128 offset + DW_OP_piece = 0x93, // 1 ULEB128 size of piece addressed + DW_OP_deref_size = 0x94, // 1 1-byte size of data retrieved + DW_OP_xderef_size = 0x95, // 1 1-byte size of data retrieved + DW_OP_nop = 0x96, // 0 + DW_OP_push_object_address = 0x97, // 0 + DW_OP_call2 = 0x98, // 1 2-byte offset of DIE + DW_OP_call4 = 0x99, // 1 4-byte offset of DIE + DW_OP_call_ref = 0x9a, // 1 4- or 8-byte offset of DIE + DW_OP_form_tls_address = 0x9b, // 0 + DW_OP_call_frame_cfa = 0x9c, // 0 + DW_OP_bit_piece = 0x9d, // 2 + DW_OP_lo_user = 0xe0, + DW_OP_hi_user = 0xff, +}; + +// Table 25 +enum +{ + DW_ATE_address = 0x01, + DW_ATE_boolean = 0x02, + DW_ATE_complex_float = 0x03, + DW_ATE_float = 0x04, + DW_ATE_signed = 0x05, + DW_ATE_signed_char = 0x06, + DW_ATE_unsigned = 0x07, + DW_ATE_unsigned_char = 0x08, + DW_ATE_imaginary_float = 0x09, + DW_ATE_packed_decimal = 0x0a, + DW_ATE_numeric_string = 0x0b, + DW_ATE_edited = 0x0c, + DW_ATE_signed_fixed = 0x0d, + DW_ATE_unsigned_fixed = 0x0e, + DW_ATE_decimal_float = 0x0f, + DW_ATE_lo_user = 0x80, + DW_ATE_hi_user = 0xff, +}; + +// Table 26 +enum +{ + DW_DS_unsigned = 0x01, + DW_DS_leading_overpunch = 0x02, + DW_DS_trailing_overpunch = 0x03, + DW_DS_leading_separate = 0x04, + DW_DS_trailing_separate = 0x05, +}; + +// Table 27 +enum +{ + DW_END_default = 0x00, + DW_END_big = 0x01, + DW_END_little = 0x02, + DW_END_lo_user = 0x40, + DW_END_hi_user = 0xff, +}; + +// Table 28 +enum +{ + DW_ACCESS_public = 0x01, + DW_ACCESS_protected = 0x02, + DW_ACCESS_private = 0x03, +}; + +// Table 29 +enum +{ + DW_VIS_local = 0x01, + DW_VIS_exported = 0x02, + DW_VIS_qualified = 0x03, +}; + +// Table 30 +enum +{ + DW_VIRTUALITY_none = 0x00, + DW_VIRTUALITY_virtual = 0x01, + DW_VIRTUALITY_pure_virtual = 0x02, +}; + +// Table 31 +enum +{ + DW_LANG_C89 = 0x0001, + DW_LANG_C = 0x0002, + DW_LANG_Ada83 = 0x0003, + DW_LANG_C_plus_plus = 0x0004, + DW_LANG_Cobol74 = 0x0005, + DW_LANG_Cobol85 = 0x0006, + DW_LANG_Fortran77 = 0x0007, + DW_LANG_Fortran90 = 0x0008, + DW_LANG_Pascal83 = 0x0009, + DW_LANG_Modula2 = 0x000a, + // Dwarf3 + DW_LANG_Java = 0x000b, + DW_LANG_C99 = 0x000c, + DW_LANG_Ada95 = 0x000d, + DW_LANG_Fortran95 = 0x000e, + DW_LANG_PLI = 0x000f, + DW_LANG_ObjC = 0x0010, + DW_LANG_ObjC_plus_plus = 0x0011, + DW_LANG_UPC = 0x0012, + DW_LANG_D = 0x0013, + // Dwarf4 + DW_LANG_Python = 0x0014, + // Dwarf5 + DW_LANG_Go = 0x0016, + + DW_LANG_lo_user = 0x8000, + DW_LANG_hi_user = 0xffff, +}; + +// Table 32 +enum +{ + DW_ID_case_sensitive = 0x00, + DW_ID_up_case = 0x01, + DW_ID_down_case = 0x02, + DW_ID_case_insensitive = 0x03, +}; + +// Table 33 +enum +{ + DW_CC_normal = 0x01, + DW_CC_program = 0x02, + DW_CC_nocall = 0x03, + DW_CC_lo_user = 0x40, + DW_CC_hi_user = 0xff, +}; + +// Table 34 +enum +{ + DW_INL_not_inlined = 0x00, + DW_INL_inlined = 0x01, + DW_INL_declared_not_inlined = 0x02, + DW_INL_declared_inlined = 0x03, +}; + +// Table 35 +enum +{ + DW_ORD_row_major = 0x00, + DW_ORD_col_major = 0x01, +}; + +// Table 36 +enum +{ + DW_DSC_label = 0x00, + DW_DSC_range = 0x01, +}; + +// Table 37 +enum +{ + DW_LNS_copy = 0x01, + DW_LNS_advance_pc = 0x02, + DW_LNS_advance_line = 0x03, + DW_LNS_set_file = 0x04, + DW_LNS_set_column = 0x05, + DW_LNS_negate_stmt = 0x06, + DW_LNS_set_basic_block = 0x07, + DW_LNS_const_add_pc = 0x08, + DW_LNS_fixed_advance_pc = 0x09, + // Dwarf3 + DW_LNS_set_prologue_end = 0x0a, + DW_LNS_set_epilogue_begin = 0x0b, + DW_LNS_set_isa = 0x0c, +}; + +// Table 38 +enum +{ + DW_LNE_end_sequence = 0x01, + DW_LNE_set_address = 0x02, + DW_LNE_define_file = 0x03, + DW_LNE_lo_user = 0x80, + DW_LNE_hi_user = 0xff, +}; + +// Table 39 +enum +{ + DW_MACINFO_define = 0x01, + DW_MACINFO_undef = 0x02, + DW_MACINFO_start_file = 0x03, + DW_MACINFO_end_file = 0x04, + DW_MACINFO_vendor_ext = 0xff, +}; + +// Table 40. +enum +{ // operand,... + DW_CFA_nop = 0x00, + DW_CFA_set_loc = 0x01, // address + DW_CFA_advance_loc1 = 0x02, // 1-byte delta + DW_CFA_advance_loc2 = 0x03, // 2-byte delta + DW_CFA_advance_loc4 = 0x04, // 4-byte delta + DW_CFA_offset_extended = 0x05, // ULEB128 register, ULEB128 offset + DW_CFA_restore_extended = 0x06, // ULEB128 register + DW_CFA_undefined = 0x07, // ULEB128 register + DW_CFA_same_value = 0x08, // ULEB128 register + DW_CFA_register = 0x09, // ULEB128 register, ULEB128 register + DW_CFA_remember_state = 0x0a, + DW_CFA_restore_state = 0x0b, + DW_CFA_def_cfa = 0x0c, // ULEB128 register, ULEB128 offset + DW_CFA_def_cfa_register = 0x0d, // ULEB128 register + DW_CFA_def_cfa_offset = 0x0e, // ULEB128 offset + DW_CFA_def_cfa_expression = 0x0f, // BLOCK + DW_CFA_expression = 0x10, // ULEB128 register, BLOCK + DW_CFA_offset_extended_sf = 0x11, // ULEB128 register, SLEB128 offset + DW_CFA_def_cfa_sf = 0x12, // ULEB128 register, SLEB128 offset + DW_CFA_def_cfa_offset_sf = 0x13, // SLEB128 offset + DW_CFA_val_offset = 0x14, // ULEB128, ULEB128 + DW_CFA_val_offset_sf = 0x15, // ULEB128, SLEB128 + DW_CFA_val_expression = 0x16, // ULEB128, BLOCK + + DW_CFA_lo_user = 0x1c, + DW_CFA_hi_user = 0x3f, + + // Opcodes that take an addend operand. + DW_CFA_advance_loc = 0x1<<6, // +delta + DW_CFA_offset = 0x2<<6, // +register (ULEB128 offset) + DW_CFA_restore = 0x3<<6, // +register +}; diff -r d8d00747375b sys/src/cmd/ld/elf.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/src/cmd/ld/elf.c Mon Nov 14 17:35:25 2011 +0100 @@ -0,0 +1,577 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "l.h" +#include "lib.h" +#include "../ld/elf.h" + +/* + * We use the 64-bit data structures on both 32- and 64-bit machines + * in order to write the code just once. The 64-bit data structure is + * written in the 32-bit format on the 32-bit machines. + */ +#define NSECT 32 + +int iself; + +static int elf64; +static ElfEhdr hdr; +static ElfPhdr *phdr[NSECT]; +static ElfShdr *shdr[NSECT]; +static char *interp; + +typedef struct Elfstring Elfstring; +struct Elfstring +{ + char *s; + int off; +}; + +static Elfstring elfstr[100]; +static int nelfstr; + +/* + Initialize the global variable that describes the ELF header. It will be updated as + we write section and prog headers. + */ +void +elfinit(void) +{ + iself = 1; + + switch(thechar) { + // 64-bit architectures + case '6': + elf64 = 1; + hdr.phoff = ELF64HDRSIZE; /* Must be be ELF64HDRSIZE: first PHdr must follow ELF header */ + hdr.shoff = ELF64HDRSIZE; /* Will move as we add PHeaders */ + hdr.ehsize = ELF64HDRSIZE; /* Must be ELF64HDRSIZE */ + hdr.phentsize = ELF64PHDRSIZE; /* Must be ELF64PHDRSIZE */ + hdr.shentsize = ELF64SHDRSIZE; /* Must be ELF64SHDRSIZE */ + break; + + // 32-bit architectures + default: + hdr.phoff = ELF32HDRSIZE; /* Must be be ELF32HDRSIZE: first PHdr must follow ELF header */ + hdr.shoff = ELF32HDRSIZE; /* Will move as we add PHeaders */ + hdr.ehsize = ELF32HDRSIZE; /* Must be ELF32HDRSIZE */ + hdr.phentsize = ELF32PHDRSIZE; /* Must be ELF32PHDRSIZE */ + hdr.shentsize = ELF32SHDRSIZE; /* Must be ELF32SHDRSIZE */ + } +} + +void +elf64phdr(ElfPhdr *e) +{ + LPUT(e->type); + LPUT(e->flags); + VPUT(e->off); + VPUT(e->vaddr); + VPUT(e->paddr); + VPUT(e->filesz); + VPUT(e->memsz); + VPUT(e->align); +} + +void +elf32phdr(ElfPhdr *e) +{ + int frag; + + if(e->type == PT_LOAD) { + // Correct ELF loaders will do this implicitly, + // but buggy ELF loaders like the one in some + // versions of QEMU won't. + frag = e->vaddr&(e->align-1); + e->off -= frag; + e->vaddr -= frag; + e->paddr -= frag; + e->filesz += frag; + e->memsz += frag; + } + LPUT(e->type); + LPUT(e->off); + LPUT(e->vaddr); + LPUT(e->paddr); + LPUT(e->filesz); + LPUT(e->memsz); + LPUT(e->flags); + LPUT(e->align); +} + +void +elf64shdr(ElfShdr *e) +{ + LPUT(e->name); + LPUT(e->type); + VPUT(e->flags); + VPUT(e->addr); + VPUT(e->off); + VPUT(e->size); + LPUT(e->link); + LPUT(e->info); + VPUT(e->addralign); + VPUT(e->entsize); +} + +void +elf32shdr(ElfShdr *e) +{ + LPUT(e->name); + LPUT(e->type); + LPUT(e->flags); + LPUT(e->addr); + LPUT(e->off); + LPUT(e->size); + LPUT(e->link); + LPUT(e->info); + LPUT(e->addralign); + LPUT(e->entsize); +} + +uint32 +elfwriteshdrs(void) +{ + int i; + + if (elf64) { + for (i = 0; i < hdr.shnum; i++) + elf64shdr(shdr[i]); + return hdr.shnum * ELF64SHDRSIZE; + } + for (i = 0; i < hdr.shnum; i++) + elf32shdr(shdr[i]); + return hdr.shnum * ELF32SHDRSIZE; +} + +void +elfsetstring(char *s, int off) +{ + if(nelfstr >= nelem(elfstr)) { + diag("too many elf strings"); + errorexit(); + } + elfstr[nelfstr].s = s; + elfstr[nelfstr].off = off; + nelfstr++; +} + +uint32 +elfwritephdrs(void) +{ + int i; + + if (elf64) { + for (i = 0; i < hdr.phnum; i++) + elf64phdr(phdr[i]); + return hdr.phnum * ELF64PHDRSIZE; + } + for (i = 0; i < hdr.phnum; i++) + elf32phdr(phdr[i]); + return hdr.phnum * ELF32PHDRSIZE; +} + +ElfPhdr* +newElfPhdr(void) +{ + ElfPhdr *e; + + e = mal(sizeof *e); + if (hdr.phnum >= NSECT) + diag("too many phdrs"); + else + phdr[hdr.phnum++] = e; + if (elf64) + hdr.shoff += ELF64PHDRSIZE; + else + hdr.shoff += ELF32PHDRSIZE; + return e; +} + +ElfShdr* +newElfShstrtab(vlong name) +{ + hdr.shstrndx = hdr.shnum; + return newElfShdr(name); +} + +ElfShdr* +newElfShdr(vlong name) +{ + ElfShdr *e; + + e = mal(sizeof *e); + e->name = name; + if (hdr.shnum >= NSECT) { + diag("too many shdrs"); + } else { + shdr[hdr.shnum++] = e; + } + return e; +} + +ElfEhdr* +getElfEhdr(void) +{ + return &hdr; +} + +uint32 +elf64writehdr(void) +{ + int i; + + for (i = 0; i < EI_NIDENT; i++) + cput(hdr.ident[i]); + WPUT(hdr.type); + WPUT(hdr.machine); + LPUT(hdr.version); + VPUT(hdr.entry); + VPUT(hdr.phoff); + VPUT(hdr.shoff); + LPUT(hdr.flags); + WPUT(hdr.ehsize); + WPUT(hdr.phentsize); + WPUT(hdr.phnum); + WPUT(hdr.shentsize); + WPUT(hdr.shnum); + WPUT(hdr.shstrndx); + return ELF64HDRSIZE; +} + +uint32 +elf32writehdr(void) +{ + int i; + + for (i = 0; i < EI_NIDENT; i++) + cput(hdr.ident[i]); + WPUT(hdr.type); + WPUT(hdr.machine); + LPUT(hdr.version); + LPUT(hdr.entry); + LPUT(hdr.phoff); + LPUT(hdr.shoff); + LPUT(hdr.flags); + WPUT(hdr.ehsize); + WPUT(hdr.phentsize); + WPUT(hdr.phnum); + WPUT(hdr.shentsize); + WPUT(hdr.shnum); + WPUT(hdr.shstrndx); + return ELF32HDRSIZE; +} + +uint32 +elfwritehdr(void) +{ + if(elf64) + return elf64writehdr(); + return elf32writehdr(); +} + +/* Taken directly from the definition document for ELF64 */ +uint32 +elfhash(uchar *name) +{ + uint32 h = 0, g; + while (*name) { + h = (h << 4) + *name++; + if (g = h & 0xf0000000) + h ^= g >> 24; + h &= 0x0fffffff; + } + return h; +} + +void +elfwritedynent(Sym *s, int tag, uint64 val) +{ + if(elf64) { + adduint64(s, tag); + adduint64(s, val); + } else { + adduint32(s, tag); + adduint32(s, val); + } +} + +void +elfwritedynentsym(Sym *s, int tag, Sym *t) +{ + if(elf64) + adduint64(s, tag); + else + adduint32(s, tag); + addaddr(s, t); +} + +void +elfwritedynentsymsize(Sym *s, int tag, Sym *t) +{ + if(elf64) + adduint64(s, tag); + else + adduint32(s, tag); + addsize(s, t); +} + +int +elfwriteinterp(void) +{ + int n; + + if(interp == nil) + return 0; + + n = strlen(interp)+1; + cseek(ELFRESERVE-n); + cwrite(interp, n); + return n; +} + +void +elfinterp(ElfShdr *sh, uint64 startva, char *p) +{ + int n; + + interp = p; + n = strlen(interp)+1; + sh->addr = startva + ELFRESERVE - n; + sh->off = ELFRESERVE - n; + sh->size = n; +} + +extern int nelfsym; +int elfverneed; + +typedef struct Elfaux Elfaux; +typedef struct Elflib Elflib; + +struct Elflib +{ + Elflib *next; + Elfaux *aux; + char *file; +}; + +struct Elfaux +{ + Elfaux *next; + int num; + char *vers; +}; + +Elfaux* +addelflib(Elflib **list, char *file, char *vers) +{ + Elflib *lib; + Elfaux *aux; + + for(lib=*list; lib; lib=lib->next) + if(strcmp(lib->file, file) == 0) + goto havelib; + lib = mal(sizeof *lib); + lib->next = *list; + lib->file = file; + *list = lib; +havelib: + for(aux=lib->aux; aux; aux=aux->next) + if(strcmp(aux->vers, vers) == 0) + goto haveaux; + aux = mal(sizeof *aux); + aux->next = lib->aux; + aux->vers = vers; + lib->aux = aux; +haveaux: + return aux; +} + +void +elfdynhash(void) +{ + Sym *s, *sy, *dynstr; + int i, j, nbucket, b, nfile; + uint32 hc, *chain, *buckets; + int nsym; + char *name; + Elfaux **need; + Elflib *needlib; + Elflib *l; + Elfaux *x; + + if(!iself) + return; + + nsym = nelfsym; + s = lookup(".hash", 0); + s->type = SELFROSECT; + s->reachable = 1; + + i = nsym; + nbucket = 1; + while(i > 0) { + ++nbucket; + i >>= 1; + } + + needlib = nil; + need = malloc(nsym * sizeof need[0]); + chain = malloc(nsym * sizeof chain[0]); + buckets = malloc(nbucket * sizeof buckets[0]); + if(need == nil || chain == nil || buckets == nil) { + cursym = nil; + diag("out of memory"); + errorexit(); + } + memset(need, 0, nsym * sizeof need[0]); + memset(chain, 0, nsym * sizeof chain[0]); + memset(buckets, 0, nbucket * sizeof buckets[0]); + for(sy=allsym; sy!=S; sy=sy->allsym) { + if (sy->dynid <= 0) + continue; + + if(sy->dynimpvers) + need[sy->dynid] = addelflib(&needlib, sy->dynimplib, sy->dynimpvers); + + name = sy->dynimpname; + if(name == nil) + name = sy->name; + hc = elfhash((uchar*)name); + + b = hc % nbucket; + chain[sy->dynid] = buckets[b]; + buckets[b] = sy->dynid; + } + + adduint32(s, nbucket); + adduint32(s, nsym); + for(i = 0; inext) { + nfile++; + // header + adduint16(s, 1); // table version + j = 0; + for(x=l->aux; x; x=x->next) + j++; + adduint16(s, j); // aux count + adduint32(s, addstring(dynstr, l->file)); // file string offset + adduint32(s, 16); // offset from header to first aux + if(l->next) + adduint32(s, 16+j*16); // offset from this header to next + else + adduint32(s, 0); + + for(x=l->aux; x; x=x->next) { + x->num = i++; + // aux struct + adduint32(s, elfhash((uchar*)x->vers)); // hash + adduint16(s, 0); // flags + adduint16(s, x->num); // other - index we refer to this by + adduint32(s, addstring(dynstr, x->vers)); // version string offset + if(x->next) + adduint32(s, 16); // offset from this aux to next + else + adduint32(s, 0); + } + } + + // version references + s = lookup(".gnu.version", 0); + for(i=0; inum); + } + + free(need); + + s = lookup(".dynamic", 0); + elfverneed = nfile; + if(elfverneed) { + elfwritedynentsym(s, DT_VERNEED, lookup(".gnu.version_r", 0)); + elfwritedynent(s, DT_VERNEEDNUM, nfile); + elfwritedynentsym(s, DT_VERSYM, lookup(".gnu.version", 0)); + } + elfwritedynent(s, DT_NULL, 0); +} + +ElfPhdr* +elfphload(Segment *seg) +{ + ElfPhdr *ph; + + ph = newElfPhdr(); + ph->type = PT_LOAD; + if(seg->rwx & 4) + ph->flags |= PF_R; + if(seg->rwx & 2) + ph->flags |= PF_W; + if(seg->rwx & 1) + ph->flags |= PF_X; + ph->vaddr = seg->vaddr; + ph->paddr = seg->vaddr; + ph->memsz = seg->len; + ph->off = seg->fileoff; + ph->filesz = seg->filelen; + ph->align = INITRND; + + return ph; +} + +ElfShdr* +elfshbits(Section *sect) +{ + int i, off; + ElfShdr *sh; + + for(i=0; iname, elfstr[i].s) == 0) { + off = elfstr[i].off; + goto found; + } + } + diag("cannot find elf name %s", sect->name); + errorexit(); + return nil; + +found: + for(i=0; iname == off) + return sh; + } + + sh = newElfShdr(off); + if(sect->vaddr < sect->seg->vaddr + sect->seg->filelen) + sh->type = SHT_PROGBITS; + else + sh->type = SHT_NOBITS; + sh->flags = SHF_ALLOC; + if(sect->rwx & 1) + sh->flags |= SHF_EXECINSTR; + if(sect->rwx & 2) + sh->flags |= SHF_WRITE; + sh->addr = sect->vaddr; + sh->addralign = PtrSize; + sh->size = sect->len; + sh->off = sect->seg->fileoff + sect->vaddr - sect->seg->vaddr; + + return sh; +} diff -r d8d00747375b sys/src/cmd/ld/elf.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/src/cmd/ld/elf.h Mon Nov 14 17:35:25 2011 +0100 @@ -0,0 +1,989 @@ +/* + * Derived from: + * $FreeBSD: src/sys/sys/elf32.h,v 1.8.14.1 2005/12/30 22:13:58 marcel Exp $ + * $FreeBSD: src/sys/sys/elf64.h,v 1.10.14.1 2005/12/30 22:13:58 marcel Exp $ + * $FreeBSD: src/sys/sys/elf_common.h,v 1.15.8.1 2005/12/30 22:13:58 marcel Exp $ + * $FreeBSD: src/sys/alpha/include/elf.h,v 1.14 2003/09/25 01:10:22 peter Exp $ + * $FreeBSD: src/sys/amd64/include/elf.h,v 1.18 2004/08/03 08:21:48 dfr Exp $ + * $FreeBSD: src/sys/arm/include/elf.h,v 1.5.2.1 2006/06/30 21:42:52 cognet Exp $ + * $FreeBSD: src/sys/i386/include/elf.h,v 1.16 2004/08/02 19:12:17 dfr Exp $ + * $FreeBSD: src/sys/powerpc/include/elf.h,v 1.7 2004/11/02 09:47:01 ssouhlal Exp $ + * $FreeBSD: src/sys/sparc64/include/elf.h,v 1.12 2003/09/25 01:10:26 peter Exp $ + * + * Copyright (c) 1996-1998 John D. Polstra. All rights reserved. + * Copyright (c) 2001 David E. O'Brien + * Portions Copyright 2009 The Go Authors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +/* + * ELF definitions that are independent of architecture or word size. + */ + +/* + * Note header. The ".note" section contains an array of notes. Each + * begins with this header, aligned to a word boundary. Immediately + * following the note header is n_namesz bytes of name, padded to the + * next word boundary. Then comes n_descsz bytes of descriptor, again + * padded to a word boundary. The values of n_namesz and n_descsz do + * not include the padding. + */ + +typedef struct { + uint32 n_namesz; /* Length of name. */ + uint32 n_descsz; /* Length of descriptor. */ + uint32 n_type; /* Type of this note. */ +} Elf_Note; + +/* Indexes into the e_ident array. Keep synced with + http://www.sco.com/developer/gabi/ch4.eheader.html */ +#define EI_MAG0 0 /* Magic number, byte 0. */ +#define EI_MAG1 1 /* Magic number, byte 1. */ +#define EI_MAG2 2 /* Magic number, byte 2. */ +#define EI_MAG3 3 /* Magic number, byte 3. */ +#define EI_CLASS 4 /* Class of machine. */ +#define EI_DATA 5 /* Data format. */ +#define EI_VERSION 6 /* ELF format version. */ +#define EI_OSABI 7 /* Operating system / ABI identification */ +#define EI_ABIVERSION 8 /* ABI version */ +#define OLD_EI_BRAND 8 /* Start of architecture identification. */ +#define EI_PAD 9 /* Start of padding (per SVR4 ABI). */ +#define EI_NIDENT 16 /* Size of e_ident array. */ + +/* Values for the magic number bytes. */ +#define ELFMAG0 0x7f +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' +#define ELFMAG "\177ELF" /* magic string */ +#define SELFMAG 4 /* magic string size */ + +/* Values for e_ident[EI_VERSION] and e_version. */ +#define EV_NONE 0 +#define EV_CURRENT 1 + +/* Values for e_ident[EI_CLASS]. */ +#define ELFCLASSNONE 0 /* Unknown class. */ +#define ELFCLASS32 1 /* 32-bit architecture. */ +#define ELFCLASS64 2 /* 64-bit architecture. */ + +/* Values for e_ident[EI_DATA]. */ +#define ELFDATANONE 0 /* Unknown data format. */ +#define ELFDATA2LSB 1 /* 2's complement little-endian. */ +#define ELFDATA2MSB 2 /* 2's complement big-endian. */ + +/* Values for e_ident[EI_OSABI]. */ +#define ELFOSABI_NONE 0 /* UNIX System V ABI */ +#define ELFOSABI_HPUX 1 /* HP-UX operating system */ +#define ELFOSABI_NETBSD 2 /* NetBSD */ +#define ELFOSABI_LINUX 3 /* GNU/Linux */ +#define ELFOSABI_HURD 4 /* GNU/Hurd */ +#define ELFOSABI_86OPEN 5 /* 86Open common IA32 ABI */ +#define ELFOSABI_SOLARIS 6 /* Solaris */ +#define ELFOSABI_AIX 7 /* AIX */ +#define ELFOSABI_IRIX 8 /* IRIX */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD */ +#define ELFOSABI_TRU64 10 /* TRU64 UNIX */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD */ +#define ELFOSABI_OPENVMS 13 /* Open VMS */ +#define ELFOSABI_NSK 14 /* HP Non-Stop Kernel */ +#define ELFOSABI_ARM 97 /* ARM */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ + +#define ELFOSABI_SYSV ELFOSABI_NONE /* symbol used in old spec */ +#define ELFOSABI_MONTEREY ELFOSABI_AIX /* Monterey */ + +/* e_ident */ +#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \ + (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \ + (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \ + (ehdr).e_ident[EI_MAG3] == ELFMAG3) + +/* Values for e_type. */ +#define ET_NONE 0 /* Unknown type. */ +#define ET_REL 1 /* Relocatable. */ +#define ET_EXEC 2 /* Executable. */ +#define ET_DYN 3 /* Shared object. */ +#define ET_CORE 4 /* Core file. */ +#define ET_LOOS 0xfe00 /* First operating system specific. */ +#define ET_HIOS 0xfeff /* Last operating system-specific. */ +#define ET_LOPROC 0xff00 /* First processor-specific. */ +#define ET_HIPROC 0xffff /* Last processor-specific. */ + +/* Values for e_machine. */ +#define EM_NONE 0 /* Unknown machine. */ +#define EM_M32 1 /* AT&T WE32100. */ +#define EM_SPARC 2 /* Sun SPARC. */ +#define EM_386 3 /* Intel i386. */ +#define EM_68K 4 /* Motorola 68000. */ +#define EM_88K 5 /* Motorola 88000. */ +#define EM_860 7 /* Intel i860. */ +#define EM_MIPS 8 /* MIPS R3000 Big-Endian only. */ +#define EM_S370 9 /* IBM System/370. */ +#define EM_MIPS_RS3_LE 10 /* MIPS R3000 Little-Endian. */ +#define EM_PARISC 15 /* HP PA-RISC. */ +#define EM_VPP500 17 /* Fujitsu VPP500. */ +#define EM_SPARC32PLUS 18 /* SPARC v8plus. */ +#define EM_960 19 /* Intel 80960. */ +#define EM_PPC 20 /* PowerPC 32-bit. */ +#define EM_PPC64 21 /* PowerPC 64-bit. */ +#define EM_S390 22 /* IBM System/390. */ +#define EM_V800 36 /* NEC V800. */ +#define EM_FR20 37 /* Fujitsu FR20. */ +#define EM_RH32 38 /* TRW RH-32. */ +#define EM_RCE 39 /* Motorola RCE. */ +#define EM_ARM 40 /* ARM. */ +#define EM_SH 42 /* Hitachi SH. */ +#define EM_SPARCV9 43 /* SPARC v9 64-bit. */ +#define EM_TRICORE 44 /* Siemens TriCore embedded processor. */ +#define EM_ARC 45 /* Argonaut RISC Core. */ +#define EM_H8_300 46 /* Hitachi H8/300. */ +#define EM_H8_300H 47 /* Hitachi H8/300H. */ +#define EM_H8S 48 /* Hitachi H8S. */ +#define EM_H8_500 49 /* Hitachi H8/500. */ +#define EM_IA_64 50 /* Intel IA-64 Processor. */ +#define EM_MIPS_X 51 /* Stanford MIPS-X. */ +#define EM_COLDFIRE 52 /* Motorola ColdFire. */ +#define EM_68HC12 53 /* Motorola M68HC12. */ +#define EM_MMA 54 /* Fujitsu MMA. */ +#define EM_PCP 55 /* Siemens PCP. */ +#define EM_NCPU 56 /* Sony nCPU. */ +#define EM_NDR1 57 /* Denso NDR1 microprocessor. */ +#define EM_STARCORE 58 /* Motorola Star*Core processor. */ +#define EM_ME16 59 /* Toyota ME16 processor. */ +#define EM_ST100 60 /* STMicroelectronics ST100 processor. */ +#define EM_TINYJ 61 /* Advanced Logic Corp. TinyJ processor. */ +#define EM_X86_64 62 /* Advanced Micro Devices x86-64 */ + +/* Non-standard or deprecated. */ +#define EM_486 6 /* Intel i486. */ +#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */ +#define EM_ALPHA_STD 41 /* Digital Alpha (standard value). */ +#define EM_ALPHA 0x9026 /* Alpha (written in the absence of an ABI) */ + +/* Special section indexes. */ +#define SHN_UNDEF 0 /* Undefined, missing, irrelevant. */ +#define SHN_LORESERVE 0xff00 /* First of reserved range. */ +#define SHN_LOPROC 0xff00 /* First processor-specific. */ +#define SHN_HIPROC 0xff1f /* Last processor-specific. */ +#define SHN_LOOS 0xff20 /* First operating system-specific. */ +#define SHN_HIOS 0xff3f /* Last operating system-specific. */ +#define SHN_ABS 0xfff1 /* Absolute values. */ +#define SHN_COMMON 0xfff2 /* Common data. */ +#define SHN_XINDEX 0xffff /* Escape -- index stored elsewhere. */ +#define SHN_HIRESERVE 0xffff /* Last of reserved range. */ + +/* sh_type */ +#define SHT_NULL 0 /* inactive */ +#define SHT_PROGBITS 1 /* program defined information */ +#define SHT_SYMTAB 2 /* symbol table section */ +#define SHT_STRTAB 3 /* string table section */ +#define SHT_RELA 4 /* relocation section with addends */ +#define SHT_HASH 5 /* symbol hash table section */ +#define SHT_DYNAMIC 6 /* dynamic section */ +#define SHT_NOTE 7 /* note section */ +#define SHT_NOBITS 8 /* no space section */ +#define SHT_REL 9 /* relocation section - no addends */ +#define SHT_SHLIB 10 /* reserved - purpose unknown */ +#define SHT_DYNSYM 11 /* dynamic symbol table section */ +#define SHT_INIT_ARRAY 14 /* Initialization function pointers. */ +#define SHT_FINI_ARRAY 15 /* Termination function pointers. */ +#define SHT_PREINIT_ARRAY 16 /* Pre-initialization function ptrs. */ +#define SHT_GROUP 17 /* Section group. */ +#define SHT_SYMTAB_SHNDX 18 /* Section indexes (see SHN_XINDEX). */ +#define SHT_LOOS 0x60000000 /* First of OS specific semantics */ +#define SHT_HIOS 0x6fffffff /* Last of OS specific semantics */ +#define SHT_GNU_VERDEF 0x6ffffffd +#define SHT_GNU_VERNEED 0x6ffffffe +#define SHT_GNU_VERSYM 0x6fffffff +#define SHT_LOPROC 0x70000000 /* reserved range for processor */ +#define SHT_HIPROC 0x7fffffff /* specific section header types */ +#define SHT_LOUSER 0x80000000 /* reserved range for application */ +#define SHT_HIUSER 0xffffffff /* specific indexes */ + +/* Flags for sh_flags. */ +#define SHF_WRITE 0x1 /* Section contains writable data. */ +#define SHF_ALLOC 0x2 /* Section occupies memory. */ +#define SHF_EXECINSTR 0x4 /* Section contains instructions. */ +#define SHF_MERGE 0x10 /* Section may be merged. */ +#define SHF_STRINGS 0x20 /* Section contains strings. */ +#define SHF_INFO_LINK 0x40 /* sh_info holds section index. */ +#define SHF_LINK_ORDER 0x80 /* Special ordering requirements. */ +#define SHF_OS_NONCONFORMING 0x100 /* OS-specific processing required. */ +#define SHF_GROUP 0x200 /* Member of section group. */ +#define SHF_TLS 0x400 /* Section contains TLS data. */ +#define SHF_MASKOS 0x0ff00000 /* OS-specific semantics. */ +#define SHF_MASKPROC 0xf0000000 /* Processor-specific semantics. */ + +/* Values for p_type. */ +#define PT_NULL 0 /* Unused entry. */ +#define PT_LOAD 1 /* Loadable segment. */ +#define PT_DYNAMIC 2 /* Dynamic linking information segment. */ +#define PT_INTERP 3 /* Pathname of interpreter. */ +#define PT_NOTE 4 /* Auxiliary information. */ +#define PT_SHLIB 5 /* Reserved (not used). */ +#define PT_PHDR 6 /* Location of program header itself. */ +#define PT_TLS 7 /* Thread local storage segment */ +#define PT_LOOS 0x60000000 /* First OS-specific. */ +#define PT_HIOS 0x6fffffff /* Last OS-specific. */ +#define PT_LOPROC 0x70000000 /* First processor-specific type. */ +#define PT_HIPROC 0x7fffffff /* Last processor-specific type. */ +#define PT_GNU_STACK 0x6474e551 + +/* Values for p_flags. */ +#define PF_X 0x1 /* Executable. */ +#define PF_W 0x2 /* Writable. */ +#define PF_R 0x4 /* Readable. */ +#define PF_MASKOS 0x0ff00000 /* Operating system-specific. */ +#define PF_MASKPROC 0xf0000000 /* Processor-specific. */ + +/* Values for d_tag. */ +#define DT_NULL 0 /* Terminating entry. */ +/* String table offset of a needed shared library. */ +#define DT_NEEDED 1 +#define DT_PLTRELSZ 2 /* Total size in bytes of PLT relocations. */ +#define DT_PLTGOT 3 /* Processor-dependent address. */ +#define DT_HASH 4 /* Address of symbol hash table. */ +#define DT_STRTAB 5 /* Address of string table. */ +#define DT_SYMTAB 6 /* Address of symbol table. */ +#define DT_RELA 7 /* Address of ElfNN_Rela relocations. */ +#define DT_RELASZ 8 /* Total size of ElfNN_Rela relocations. */ +#define DT_RELAENT 9 /* Size of each ElfNN_Rela relocation entry. */ +#define DT_STRSZ 10 /* Size of string table. */ +#define DT_SYMENT 11 /* Size of each symbol table entry. */ +#define DT_INIT 12 /* Address of initialization function. */ +#define DT_FINI 13 /* Address of finalization function. */ +/* String table offset of shared object name. */ +#define DT_SONAME 14 +#define DT_RPATH 15 /* String table offset of library path. [sup] */ +#define DT_SYMBOLIC 16 /* Indicates "symbolic" linking. [sup] */ +#define DT_REL 17 /* Address of ElfNN_Rel relocations. */ +#define DT_RELSZ 18 /* Total size of ElfNN_Rel relocations. */ +#define DT_RELENT 19 /* Size of each ElfNN_Rel relocation. */ +#define DT_PLTREL 20 /* Type of relocation used for PLT. */ +#define DT_DEBUG 21 /* Reserved (not used). */ +/* Indicates there may be relocations in non-writable segments. [sup] */ +#define DT_TEXTREL 22 +#define DT_JMPREL 23 /* Address of PLT relocations. */ +#define DT_BIND_NOW 24 /* [sup] */ +/* Address of the array of pointers to initialization functions */ +#define DT_INIT_ARRAY 25 +/* Address of the array of pointers to termination functions */ +#define DT_FINI_ARRAY 26 +/* Size in bytes of the array of initialization functions. */ +#define DT_INIT_ARRAYSZ 27 +/* Size in bytes of the array of terminationfunctions. */ +#define DT_FINI_ARRAYSZ 28 +/* String table offset of a null-terminated library search path string. */ +#define DT_RUNPATH 29 +#define DT_FLAGS 30 /* Object specific flag values. */ +/* Values greater than or equal to DT_ENCODING and less than + DT_LOOS follow the rules for the interpretation of the d_un + union as follows: even == 'd_ptr', even == 'd_val' or none */ +#define DT_ENCODING 32 +/* Address of the array of pointers to pre-initialization functions. */ +#define DT_PREINIT_ARRAY 32 +/* Size in bytes of the array of pre-initialization functions. */ +#define DT_PREINIT_ARRAYSZ 33 +#define DT_LOOS 0x6000000d /* First OS-specific */ +#define DT_HIOS 0x6ffff000 /* Last OS-specific */ +#define DT_LOPROC 0x70000000 /* First processor-specific type. */ +#define DT_HIPROC 0x7fffffff /* Last processor-specific type. */ + +#define DT_VERNEED 0x6ffffffe +#define DT_VERNEEDNUM 0x6fffffff +#define DT_VERSYM 0x6ffffff0 + +/* Values for DT_FLAGS */ +/* Indicates that the object being loaded may make reference to + the $ORIGIN substitution string */ +#define DF_ORIGIN 0x0001 +#define DF_SYMBOLIC 0x0002 /* Indicates "symbolic" linking. */ +/* Indicates there may be relocations in non-writable segments. */ +#define DF_TEXTREL 0x0004 +/* Indicates that the dynamic linker should process all + relocations for the object containing this entry before + transferring control to the program. */ +#define DF_BIND_NOW 0x0008 +/* Indicates that the shared object or executable contains code + using a static thread-local storage scheme. */ +#define DF_STATIC_TLS 0x0010 + +/* Values for n_type. Used in core files. */ +#define NT_PRSTATUS 1 /* Process status. */ +#define NT_FPREGSET 2 /* Floating point registers. */ +#define NT_PRPSINFO 3 /* Process state info. */ + +/* Symbol Binding - ELFNN_ST_BIND - st_info */ +#define STB_LOCAL 0 /* Local symbol */ +#define STB_GLOBAL 1 /* Global symbol */ +#define STB_WEAK 2 /* like global - lower precedence */ +#define STB_LOOS 10 /* Reserved range for operating system */ +#define STB_HIOS 12 /* specific semantics. */ +#define STB_LOPROC 13 /* reserved range for processor */ +#define STB_HIPROC 15 /* specific semantics. */ + +/* Symbol type - ELFNN_ST_TYPE - st_info */ +#define STT_NOTYPE 0 /* Unspecified type. */ +#define STT_OBJECT 1 /* Data object. */ +#define STT_FUNC 2 /* Function. */ +#define STT_SECTION 3 /* Section. */ +#define STT_FILE 4 /* Source file. */ +#define STT_COMMON 5 /* Uninitialized common block. */ +#define STT_TLS 6 /* TLS object. */ +#define STT_LOOS 10 /* Reserved range for operating system */ +#define STT_HIOS 12 /* specific semantics. */ +#define STT_LOPROC 13 /* reserved range for processor */ +#define STT_HIPROC 15 /* specific semantics. */ + +/* Symbol visibility - ELFNN_ST_VISIBILITY - st_other */ +#define STV_DEFAULT 0x0 /* Default visibility (see binding). */ +#define STV_INTERNAL 0x1 /* Special meaning in relocatable objects. */ +#define STV_HIDDEN 0x2 /* Not visible. */ +#define STV_PROTECTED 0x3 /* Visible but not preemptible. */ + +/* Special symbol table indexes. */ +#define STN_UNDEF 0 /* Undefined symbol index. */ + +/* + * ELF definitions common to all 32-bit architectures. + */ + +typedef uint32 Elf32_Addr; +typedef uint16 Elf32_Half; +typedef uint32 Elf32_Off; +typedef int32 Elf32_Sword; +typedef uint32 Elf32_Word; + +typedef Elf32_Word Elf32_Hashelt; + +/* Non-standard class-dependent datatype used for abstraction. */ +typedef Elf32_Word Elf32_Size; +typedef Elf32_Sword Elf32_Ssize; + +/* + * ELF header. + */ + +typedef struct { + unsigned char ident[EI_NIDENT]; /* File identification. */ + Elf32_Half type; /* File type. */ + Elf32_Half machine; /* Machine architecture. */ + Elf32_Word version; /* ELF format version. */ + Elf32_Addr entry; /* Entry point. */ + Elf32_Off phoff; /* Program header file offset. */ + Elf32_Off shoff; /* Section header file offset. */ + Elf32_Word flags; /* Architecture-specific flags. */ + Elf32_Half ehsize; /* Size of ELF header in bytes. */ + Elf32_Half phentsize; /* Size of program header entry. */ + Elf32_Half phnum; /* Number of program header entries. */ + Elf32_Half shentsize; /* Size of section header entry. */ + Elf32_Half shnum; /* Number of section header entries. */ + Elf32_Half shstrndx; /* Section name strings section. */ +} Elf32_Ehdr; + +/* + * Section header. + */ + +typedef struct { + Elf32_Word name; /* Section name (index into the + section header string table). */ + Elf32_Word type; /* Section type. */ + Elf32_Word flags; /* Section flags. */ + Elf32_Addr vaddr; /* Address in memory image. */ + Elf32_Off off; /* Offset in file. */ + Elf32_Word size; /* Size in bytes. */ + Elf32_Word link; /* Index of a related section. */ + Elf32_Word info; /* Depends on section type. */ + Elf32_Word addralign; /* Alignment in bytes. */ + Elf32_Word entsize; /* Size of each entry in section. */ +} Elf32_Shdr; + +/* + * Program header. + */ + +typedef struct { + Elf32_Word type; /* Entry type. */ + Elf32_Off off; /* File offset of contents. */ + Elf32_Addr vaddr; /* Virtual address in memory image. */ + Elf32_Addr paddr; /* Physical address (not used). */ + Elf32_Word filesz; /* Size of contents in file. */ + Elf32_Word memsz; /* Size of contents in memory. */ + Elf32_Word flags; /* Access permission flags. */ + Elf32_Word align; /* Alignment in memory and file. */ +} Elf32_Phdr; + +/* + * Dynamic structure. The ".dynamic" section contains an array of them. + */ + +typedef struct { + Elf32_Sword d_tag; /* Entry type. */ + union { + Elf32_Word d_val; /* Integer value. */ + Elf32_Addr d_ptr; /* Address value. */ + } d_un; +} Elf32_Dyn; + +/* + * Relocation entries. + */ + +/* Relocations that don't need an addend field. */ +typedef struct { + Elf32_Addr off; /* Location to be relocated. */ + Elf32_Word info; /* Relocation type and symbol index. */ +} Elf32_Rel; + +/* Relocations that need an addend field. */ +typedef struct { + Elf32_Addr off; /* Location to be relocated. */ + Elf32_Word info; /* Relocation type and symbol index. */ + Elf32_Sword addend; /* Addend. */ +} Elf32_Rela; + +/* Macros for accessing the fields of r_info. */ +#define ELF32_R_SYM(info) ((info) >> 8) +#define ELF32_R_TYPE(info) ((unsigned char)(info)) + +/* Macro for constructing r_info from field values. */ +#define ELF32_R_INFO(sym, type) (((sym) << 8) + (unsigned char)(type)) + +/* + * Relocation types. + */ + +#define R_X86_64_NONE 0 /* No relocation. */ +#define R_X86_64_64 1 /* Add 64 bit symbol value. */ +#define R_X86_64_PC32 2 /* PC-relative 32 bit signed sym value. */ +#define R_X86_64_GOT32 3 /* PC-relative 32 bit GOT offset. */ +#define R_X86_64_PLT32 4 /* PC-relative 32 bit PLT offset. */ +#define R_X86_64_COPY 5 /* Copy data from shared object. */ +#define R_X86_64_GLOB_DAT 6 /* Set GOT entry to data address. */ +#define R_X86_64_JMP_SLOT 7 /* Set GOT entry to code address. */ +#define R_X86_64_RELATIVE 8 /* Add load address of shared object. */ +#define R_X86_64_GOTPCREL 9 /* Add 32 bit signed pcrel offset to GOT. */ +#define R_X86_64_32 10 /* Add 32 bit zero extended symbol value */ +#define R_X86_64_32S 11 /* Add 32 bit sign extended symbol value */ +#define R_X86_64_16 12 /* Add 16 bit zero extended symbol value */ +#define R_X86_64_PC16 13 /* Add 16 bit signed extended pc relative symbol value */ +#define R_X86_64_8 14 /* Add 8 bit zero extended symbol value */ +#define R_X86_64_PC8 15 /* Add 8 bit signed extended pc relative symbol value */ +#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */ +#define R_X86_64_DTPOFF64 17 /* Offset in TLS block */ +#define R_X86_64_TPOFF64 18 /* Offset in static TLS block */ +#define R_X86_64_TLSGD 19 /* PC relative offset to GD GOT entry */ +#define R_X86_64_TLSLD 20 /* PC relative offset to LD GOT entry */ +#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */ +#define R_X86_64_GOTTPOFF 22 /* PC relative offset to IE GOT entry */ +#define R_X86_64_TPOFF32 23 /* Offset in static TLS block */ + +#define R_X86_64_COUNT 24 /* Count of defined relocation types. */ + + +#define R_ALPHA_NONE 0 /* No reloc */ +#define R_ALPHA_REFLONG 1 /* Direct 32 bit */ +#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */ +#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */ +#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */ +#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */ +#define R_ALPHA_GPDISP 6 /* Add displacement to GP */ +#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */ +#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */ +#define R_ALPHA_SREL16 9 /* PC relative 16 bit */ +#define R_ALPHA_SREL32 10 /* PC relative 32 bit */ +#define R_ALPHA_SREL64 11 /* PC relative 64 bit */ +#define R_ALPHA_OP_PUSH 12 /* OP stack push */ +#define R_ALPHA_OP_STORE 13 /* OP stack pop and store */ +#define R_ALPHA_OP_PSUB 14 /* OP stack subtract */ +#define R_ALPHA_OP_PRSHIFT 15 /* OP stack right shift */ +#define R_ALPHA_GPVALUE 16 +#define R_ALPHA_GPRELHIGH 17 +#define R_ALPHA_GPRELLOW 18 +#define R_ALPHA_IMMED_GP_16 19 +#define R_ALPHA_IMMED_GP_HI32 20 +#define R_ALPHA_IMMED_SCN_HI32 21 +#define R_ALPHA_IMMED_BR_HI32 22 +#define R_ALPHA_IMMED_LO32 23 +#define R_ALPHA_COPY 24 /* Copy symbol at runtime */ +#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */ +#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ +#define R_ALPHA_RELATIVE 27 /* Adjust by program base */ + +#define R_ALPHA_COUNT 28 + + +#define R_ARM_NONE 0 /* No relocation. */ +#define R_ARM_PC24 1 +#define R_ARM_ABS32 2 +#define R_ARM_REL32 3 +#define R_ARM_PC13 4 +#define R_ARM_ABS16 5 +#define R_ARM_ABS12 6 +#define R_ARM_THM_ABS5 7 +#define R_ARM_ABS8 8 +#define R_ARM_SBREL32 9 +#define R_ARM_THM_PC22 10 +#define R_ARM_THM_PC8 11 +#define R_ARM_AMP_VCALL9 12 +#define R_ARM_SWI24 13 +#define R_ARM_THM_SWI8 14 +#define R_ARM_XPC25 15 +#define R_ARM_THM_XPC22 16 +#define R_ARM_COPY 20 /* Copy data from shared object. */ +#define R_ARM_GLOB_DAT 21 /* Set GOT entry to data address. */ +#define R_ARM_JUMP_SLOT 22 /* Set GOT entry to code address. */ +#define R_ARM_RELATIVE 23 /* Add load address of shared object. */ +#define R_ARM_GOTOFF 24 /* Add GOT-relative symbol address. */ +#define R_ARM_GOTPC 25 /* Add PC-relative GOT table address. */ +#define R_ARM_GOT32 26 /* Add PC-relative GOT offset. */ +#define R_ARM_PLT32 27 /* Add PC-relative PLT offset. */ +#define R_ARM_GNU_VTENTRY 100 +#define R_ARM_GNU_VTINHERIT 101 +#define R_ARM_RSBREL32 250 +#define R_ARM_THM_RPC22 251 +#define R_ARM_RREL32 252 +#define R_ARM_RABS32 253 +#define R_ARM_RPC24 254 +#define R_ARM_RBASE 255 + +#define R_ARM_COUNT 33 /* Count of defined relocation types. */ + + +#define R_386_NONE 0 /* No relocation. */ +#define R_386_32 1 /* Add symbol value. */ +#define R_386_PC32 2 /* Add PC-relative symbol value. */ +#define R_386_GOT32 3 /* Add PC-relative GOT offset. */ +#define R_386_PLT32 4 /* Add PC-relative PLT offset. */ +#define R_386_COPY 5 /* Copy data from shared object. */ +#define R_386_GLOB_DAT 6 /* Set GOT entry to data address. */ +#define R_386_JMP_SLOT 7 /* Set GOT entry to code address. */ +#define R_386_RELATIVE 8 /* Add load address of shared object. */ +#define R_386_GOTOFF 9 /* Add GOT-relative symbol address. */ +#define R_386_GOTPC 10 /* Add PC-relative GOT table address. */ +#define R_386_TLS_TPOFF 14 /* Negative offset in static TLS block */ +#define R_386_TLS_IE 15 /* Absolute address of GOT for -ve static TLS */ +#define R_386_TLS_GOTIE 16 /* GOT entry for negative static TLS block */ +#define R_386_TLS_LE 17 /* Negative offset relative to static TLS */ +#define R_386_TLS_GD 18 /* 32 bit offset to GOT (index,off) pair */ +#define R_386_TLS_LDM 19 /* 32 bit offset to GOT (index,zero) pair */ +#define R_386_TLS_GD_32 24 /* 32 bit offset to GOT (index,off) pair */ +#define R_386_TLS_GD_PUSH 25 /* pushl instruction for Sun ABI GD sequence */ +#define R_386_TLS_GD_CALL 26 /* call instruction for Sun ABI GD sequence */ +#define R_386_TLS_GD_POP 27 /* popl instruction for Sun ABI GD sequence */ +#define R_386_TLS_LDM_32 28 /* 32 bit offset to GOT (index,zero) pair */ +#define R_386_TLS_LDM_PUSH 29 /* pushl instruction for Sun ABI LD sequence */ +#define R_386_TLS_LDM_CALL 30 /* call instruction for Sun ABI LD sequence */ +#define R_386_TLS_LDM_POP 31 /* popl instruction for Sun ABI LD sequence */ +#define R_386_TLS_LDO_32 32 /* 32 bit offset from start of TLS block */ +#define R_386_TLS_IE_32 33 /* 32 bit offset to GOT static TLS offset entry */ +#define R_386_TLS_LE_32 34 /* 32 bit offset within static TLS block */ +#define R_386_TLS_DTPMOD32 35 /* GOT entry containing TLS index */ +#define R_386_TLS_DTPOFF32 36 /* GOT entry containing TLS offset */ +#define R_386_TLS_TPOFF32 37 /* GOT entry of -ve static TLS offset */ + +#define R_386_COUNT 38 /* Count of defined relocation types. */ + +#define R_PPC_NONE 0 /* No relocation. */ +#define R_PPC_ADDR32 1 +#define R_PPC_ADDR24 2 +#define R_PPC_ADDR16 3 +#define R_PPC_ADDR16_LO 4 +#define R_PPC_ADDR16_HI 5 +#define R_PPC_ADDR16_HA 6 +#define R_PPC_ADDR14 7 +#define R_PPC_ADDR14_BRTAKEN 8 +#define R_PPC_ADDR14_BRNTAKEN 9 +#define R_PPC_REL24 10 +#define R_PPC_REL14 11 +#define R_PPC_REL14_BRTAKEN 12 +#define R_PPC_REL14_BRNTAKEN 13 +#define R_PPC_GOT16 14 +#define R_PPC_GOT16_LO 15 +#define R_PPC_GOT16_HI 16 +#define R_PPC_GOT16_HA 17 +#define R_PPC_PLTREL24 18 +#define R_PPC_COPY 19 +#define R_PPC_GLOB_DAT 20 +#define R_PPC_JMP_SLOT 21 +#define R_PPC_RELATIVE 22 +#define R_PPC_LOCAL24PC 23 +#define R_PPC_UADDR32 24 +#define R_PPC_UADDR16 25 +#define R_PPC_REL32 26 +#define R_PPC_PLT32 27 +#define R_PPC_PLTREL32 28 +#define R_PPC_PLT16_LO 29 +#define R_PPC_PLT16_HI 30 +#define R_PPC_PLT16_HA 31 +#define R_PPC_SDAREL16 32 +#define R_PPC_SECTOFF 33 +#define R_PPC_SECTOFF_LO 34 +#define R_PPC_SECTOFF_HI 35 +#define R_PPC_SECTOFF_HA 36 + +#define R_PPC_COUNT 37 /* Count of defined relocation types. */ + +#define R_PPC_TLS 67 +#define R_PPC_DTPMOD32 68 +#define R_PPC_TPREL16 69 +#define R_PPC_TPREL16_LO 70 +#define R_PPC_TPREL16_HI 71 +#define R_PPC_TPREL16_HA 72 +#define R_PPC_TPREL32 73 +#define R_PPC_DTPREL16 74 +#define R_PPC_DTPREL16_LO 75 +#define R_PPC_DTPREL16_HI 76 +#define R_PPC_DTPREL16_HA 77 +#define R_PPC_DTPREL32 78 +#define R_PPC_GOT_TLSGD16 79 +#define R_PPC_GOT_TLSGD16_LO 80 +#define R_PPC_GOT_TLSGD16_HI 81 +#define R_PPC_GOT_TLSGD16_HA 82 +#define R_PPC_GOT_TLSLD16 83 +#define R_PPC_GOT_TLSLD16_LO 84 +#define R_PPC_GOT_TLSLD16_HI 85 +#define R_PPC_GOT_TLSLD16_HA 86 +#define R_PPC_GOT_TPREL16 87 +#define R_PPC_GOT_TPREL16_LO 88 +#define R_PPC_GOT_TPREL16_HI 89 +#define R_PPC_GOT_TPREL16_HA 90 + +#define R_PPC_EMB_NADDR32 101 +#define R_PPC_EMB_NADDR16 102 +#define R_PPC_EMB_NADDR16_LO 103 +#define R_PPC_EMB_NADDR16_HI 104 +#define R_PPC_EMB_NADDR16_HA 105 +#define R_PPC_EMB_SDAI16 106 +#define R_PPC_EMB_SDA2I16 107 +#define R_PPC_EMB_SDA2REL 108 +#define R_PPC_EMB_SDA21 109 +#define R_PPC_EMB_MRKREF 110 +#define R_PPC_EMB_RELSEC16 111 +#define R_PPC_EMB_RELST_LO 112 +#define R_PPC_EMB_RELST_HI 113 +#define R_PPC_EMB_RELST_HA 114 +#define R_PPC_EMB_BIT_FLD 115 +#define R_PPC_EMB_RELSDA 116 + + /* Count of defined relocation types. */ +#define R_PPC_EMB_COUNT (R_PPC_EMB_RELSDA - R_PPC_EMB_NADDR32 + 1) + + +#define R_SPARC_NONE 0 +#define R_SPARC_8 1 +#define R_SPARC_16 2 +#define R_SPARC_32 3 +#define R_SPARC_DISP8 4 +#define R_SPARC_DISP16 5 +#define R_SPARC_DISP32 6 +#define R_SPARC_WDISP30 7 +#define R_SPARC_WDISP22 8 +#define R_SPARC_HI22 9 +#define R_SPARC_22 10 +#define R_SPARC_13 11 +#define R_SPARC_LO10 12 +#define R_SPARC_GOT10 13 +#define R_SPARC_GOT13 14 +#define R_SPARC_GOT22 15 +#define R_SPARC_PC10 16 +#define R_SPARC_PC22 17 +#define R_SPARC_WPLT30 18 +#define R_SPARC_COPY 19 +#define R_SPARC_GLOB_DAT 20 +#define R_SPARC_JMP_SLOT 21 +#define R_SPARC_RELATIVE 22 +#define R_SPARC_UA32 23 +#define R_SPARC_PLT32 24 +#define R_SPARC_HIPLT22 25 +#define R_SPARC_LOPLT10 26 +#define R_SPARC_PCPLT32 27 +#define R_SPARC_PCPLT22 28 +#define R_SPARC_PCPLT10 29 +#define R_SPARC_10 30 +#define R_SPARC_11 31 +#define R_SPARC_64 32 +#define R_SPARC_OLO10 33 +#define R_SPARC_HH22 34 +#define R_SPARC_HM10 35 +#define R_SPARC_LM22 36 +#define R_SPARC_PC_HH22 37 +#define R_SPARC_PC_HM10 38 +#define R_SPARC_PC_LM22 39 +#define R_SPARC_WDISP16 40 +#define R_SPARC_WDISP19 41 +#define R_SPARC_GLOB_JMP 42 +#define R_SPARC_7 43 +#define R_SPARC_5 44 +#define R_SPARC_6 45 +#define R_SPARC_DISP64 46 +#define R_SPARC_PLT64 47 +#define R_SPARC_HIX22 48 +#define R_SPARC_LOX10 49 +#define R_SPARC_H44 50 +#define R_SPARC_M44 51 +#define R_SPARC_L44 52 +#define R_SPARC_REGISTER 53 +#define R_SPARC_UA64 54 +#define R_SPARC_UA16 55 + + +/* + * Magic number for the elf trampoline, chosen wisely to be an immediate + * value. + */ +#define ARM_MAGIC_TRAMP_NUMBER 0x5c000003 + + +/* + * Symbol table entries. + */ + +typedef struct { + Elf32_Word name; /* String table index of name. */ + Elf32_Addr value; /* Symbol value. */ + Elf32_Word size; /* Size of associated object. */ + unsigned char info; /* Type and binding information. */ + unsigned char other; /* Reserved (not used). */ + Elf32_Half shndx; /* Section index of symbol. */ +} Elf32_Sym; + +/* Macros for accessing the fields of st_info. */ +#define ELF32_ST_BIND(info) ((info) >> 4) +#define ELF32_ST_TYPE(info) ((info) & 0xf) + +/* Macro for constructing st_info from field values. */ +#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) + +/* Macro for accessing the fields of st_other. */ +#define ELF32_ST_VISIBILITY(oth) ((oth) & 0x3) + +/* + * ELF definitions common to all 64-bit architectures. + */ + +typedef uint64 Elf64_Addr; +typedef uint16 Elf64_Half; +typedef uint64 Elf64_Off; +typedef int32 Elf64_Sword; +typedef int64 Elf64_Sxword; +typedef uint32 Elf64_Word; +typedef uint64 Elf64_Xword; + +/* + * Types of dynamic symbol hash table bucket and chain elements. + * + * This is inconsistent among 64 bit architectures, so a machine dependent + * typedef is required. + */ + +#ifdef __alpha__ +typedef Elf64_Off Elf64_Hashelt; +#else +typedef Elf64_Word Elf64_Hashelt; +#endif + +/* Non-standard class-dependent datatype used for abstraction. */ +typedef Elf64_Xword Elf64_Size; +typedef Elf64_Sxword Elf64_Ssize; + +/* + * ELF header. + */ + +typedef struct { + unsigned char ident[EI_NIDENT]; /* File identification. */ + Elf64_Half type; /* File type. */ + Elf64_Half machine; /* Machine architecture. */ + Elf64_Word version; /* ELF format version. */ + Elf64_Addr entry; /* Entry point. */ + Elf64_Off phoff; /* Program header file offset. */ + Elf64_Off shoff; /* Section header file offset. */ + Elf64_Word flags; /* Architecture-specific flags. */ + Elf64_Half ehsize; /* Size of ELF header in bytes. */ + Elf64_Half phentsize; /* Size of program header entry. */ + Elf64_Half phnum; /* Number of program header entries. */ + Elf64_Half shentsize; /* Size of section header entry. */ + Elf64_Half shnum; /* Number of section header entries. */ + Elf64_Half shstrndx; /* Section name strings section. */ +} Elf64_Ehdr; + +/* + * Section header. + */ + +typedef struct { + Elf64_Word name; /* Section name (index into the + section header string table). */ + Elf64_Word type; /* Section type. */ + Elf64_Xword flags; /* Section flags. */ + Elf64_Addr addr; /* Address in memory image. */ + Elf64_Off off; /* Offset in file. */ + Elf64_Xword size; /* Size in bytes. */ + Elf64_Word link; /* Index of a related section. */ + Elf64_Word info; /* Depends on section type. */ + Elf64_Xword addralign; /* Alignment in bytes. */ + Elf64_Xword entsize; /* Size of each entry in section. */ +} Elf64_Shdr; + +/* + * Program header. + */ + +typedef struct { + Elf64_Word type; /* Entry type. */ + Elf64_Word flags; /* Access permission flags. */ + Elf64_Off off; /* File offset of contents. */ + Elf64_Addr vaddr; /* Virtual address in memory image. */ + Elf64_Addr paddr; /* Physical address (not used). */ + Elf64_Xword filesz; /* Size of contents in file. */ + Elf64_Xword memsz; /* Size of contents in memory. */ + Elf64_Xword align; /* Alignment in memory and file. */ +} Elf64_Phdr; + +/* + * Dynamic structure. The ".dynamic" section contains an array of them. + */ + +typedef struct { + Elf64_Sxword d_tag; /* Entry type. */ + union { + Elf64_Xword d_val; /* Integer value. */ + Elf64_Addr d_ptr; /* Address value. */ + } d_un; +} Elf64_Dyn; + +/* + * Relocation entries. + */ + +/* Relocations that don't need an addend field. */ +typedef struct { + Elf64_Addr off; /* Location to be relocated. */ + Elf64_Xword info; /* Relocation type and symbol index. */ +} Elf64_Rel; + +/* Relocations that need an addend field. */ +typedef struct { + Elf64_Addr off; /* Location to be relocated. */ + Elf64_Xword info; /* Relocation type and symbol index. */ + Elf64_Sxword addend; /* Addend. */ +} Elf64_Rela; + +/* Macros for accessing the fields of r_info. */ +#define ELF64_R_SYM(info) ((info) >> 32) +#define ELF64_R_TYPE(info) ((info) & 0xffffffffL) + +/* Macro for constructing r_info from field values. */ +#define ELF64_R_INFO(sym, type) ((((uint64)(sym)) << 32) + (((uint64)(type)) & 0xffffffffULL)) + +/* + * Symbol table entries. + */ + +typedef struct { + Elf64_Word name; /* String table index of name. */ + unsigned char info; /* Type and binding information. */ + unsigned char other; /* Reserved (not used). */ + Elf64_Half shndx; /* Section index of symbol. */ + Elf64_Addr value; /* Symbol value. */ + Elf64_Xword size; /* Size of associated object. */ +} Elf64_Sym; + +/* Macros for accessing the fields of st_info. */ +#define ELF64_ST_BIND(info) ((info) >> 4) +#define ELF64_ST_TYPE(info) ((info) & 0xf) + +/* Macro for constructing st_info from field values. */ +#define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) + +/* Macro for accessing the fields of st_other. */ +#define ELF64_ST_VISIBILITY(oth) ((oth) & 0x3) + +/* + * Go linker interface + */ + +#define ELF64HDRSIZE 64 +#define ELF64PHDRSIZE 56 +#define ELF64SHDRSIZE 64 +#define ELF64RELSIZE 16 +#define ELF64RELASIZE 24 +#define ELF64SYMSIZE sizeof(Elf64_Sym) + +#define ELF32HDRSIZE sizeof(Elf32_Ehdr) +#define ELF32PHDRSIZE sizeof(Elf32_Phdr) +#define ELF32SHDRSIZE sizeof(Elf32_Shdr) +#define ELF32SYMSIZE sizeof(Elf32_Sym) +#define ELF32RELSIZE 8 + +/* + * The interface uses the 64-bit structures always, + * to avoid code duplication. The writers know how to + * marshal a 32-bit representation from the 64-bit structure. + */ +typedef Elf64_Ehdr ElfEhdr; +typedef Elf64_Shdr ElfShdr; +typedef Elf64_Phdr ElfPhdr; + +void elfinit(void); +ElfEhdr *getElfEhdr(void); +ElfShdr *newElfShstrtab(vlong); +ElfShdr *newElfShdr(vlong); +ElfPhdr *newElfPhdr(void); +uint32 elfwritehdr(void); +uint32 elfwritephdrs(void); +uint32 elfwriteshdrs(void); +void elfwritedynent(Sym*, int, uint64); +void elfwritedynentsym(Sym*, int, Sym*); +void elfwritedynentsymsize(Sym*, int, Sym*); +uint32 elfhash(uchar*); +uint64 startelf(void); +uint64 endelf(void); +extern int numelfphdr; +extern int numelfshdr; +extern int iself; +extern int elfverneed; +int elfwriteinterp(void); +void elfinterp(ElfShdr*, uint64, char*); +void elfdynhash(void); +ElfPhdr* elfphload(Segment*); +ElfShdr* elfshbits(Section*); +void elfsetstring(char*, int); +void elfaddverneed(Sym*); + +EXTERN int elfstrsize; +EXTERN char* elfstrdat; +EXTERN int elftextsh; + +/* + * Total amount of space to reserve at the start of the file + * for Header, PHeaders, SHeaders, and interp. + * May waste some. + * On FreeBSD, cannot be larger than a page. + */ +#define ELFRESERVE 3072 diff -r d8d00747375b sys/src/cmd/ld/go.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/src/cmd/ld/go.c Mon Nov 14 17:35:25 2011 +0100 @@ -0,0 +1,869 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// go-specific code shared across loaders (5l, 6l, 8l). + +#include "l.h" +#include "../ld/lib.h" + +// accumulate all type information from .6 files. +// check for inconsistencies. + +// TODO: +// generate debugging section in binary. +// once the dust settles, try to move some code to +// libmach, so that other linkers and ar can share. + +/* + * package import data + */ +typedef struct Import Import; +struct Import +{ + Import *hash; // next in hash table + char *prefix; // "type", "var", "func", "const" + char *name; + char *def; + char *file; +}; +enum { + NIHASH = 1024 +}; +static Import *ihash[NIHASH]; +static int nimport; +static void imported(char *pkg, char *import); + +static int +hashstr(char *name) +{ + int h; + char *cp; + + h = 0; + for(cp = name; *cp; h += *cp++) + h *= 1119; + // not if(h < 0) h = ~h, because gcc 4.3 -O2 miscompiles it. + h &= 0xffffff; + return h; +} + +static Import * +ilookup(char *name) +{ + int h; + Import *x; + + h = hashstr(name) % NIHASH; + for(x=ihash[h]; x; x=x->hash) + if(x->name[0] == name[0] && strcmp(x->name, name) == 0) + return x; + x = mal(sizeof *x); + x->name = strdup(name); + x->hash = ihash[h]; + ihash[h] = x; + nimport++; + return x; +} + +static void loadpkgdata(char*, char*, char*, int); +static void loaddynimport(char*, char*, char*, int); +static void loaddynexport(char*, char*, char*, int); +static int parsemethod(char**, char*, char**); +static int parsepkgdata(char*, char*, char**, char*, char**, char**, char**); + +static Sym **dynexp; + +void +ldpkg(Biobuf *f, char *pkg, int64 len, char *filename, int whence) +{ + char *data, *p0, *p1, *name; + + if(debug['g']) + return; + + if((int)len != len) { + fprint(2, "%s: too much pkg data in %s\n", argv0, filename); + if(debug['u']) + errorexit(); + return; + } + data = mal(len+1); + if(Bread(f, data, len) != len) { + fprint(2, "%s: short pkg read %s\n", argv0, filename); + if(debug['u']) + errorexit(); + return; + } + data[len] = '\0'; + + // first \n$$ marks beginning of exports - skip rest of line + p0 = strstr(data, "\n$$"); + if(p0 == nil) { + if(debug['u'] && whence != ArchiveObj) { + fprint(2, "%s: cannot find export data in %s\n", argv0, filename); + errorexit(); + } + return; + } + p0 += 3; + while(*p0 != '\n' && *p0 != '\0') + p0++; + + // second marks end of exports / beginning of local data + p1 = strstr(p0, "\n$$"); + if(p1 == nil) { + fprint(2, "%s: cannot find end of exports in %s\n", argv0, filename); + if(debug['u']) + errorexit(); + return; + } + while(p0 < p1 && (*p0 == ' ' || *p0 == '\t' || *p0 == '\n')) + p0++; + if(p0 < p1) { + if(strncmp(p0, "package ", 8) != 0) { + fprint(2, "%s: bad package section in %s - %s\n", argv0, filename, p0); + if(debug['u']) + errorexit(); + return; + } + p0 += 8; + while(p0 < p1 && (*p0 == ' ' || *p0 == '\t' || *p0 == '\n')) + p0++; + name = p0; + while(p0 < p1 && *p0 != ' ' && *p0 != '\t' && *p0 != '\n') + p0++; + if(debug['u'] && whence != ArchiveObj && + (p0+6 > p1 || memcmp(p0, " safe\n", 6) != 0)) { + fprint(2, "%s: load of unsafe package %s\n", argv0, filename); + nerrors++; + errorexit(); + } + if(p0 < p1) { + if(*p0 == '\n') + *p0++ = '\0'; + else { + *p0++ = '\0'; + while(p0 < p1 && *p0++ != '\n') + ; + } + } + if(strcmp(pkg, "main") == 0 && strcmp(name, "main") != 0) { + fprint(2, "%s: %s: not package main (package %s)\n", argv0, filename, name); + nerrors++; + errorexit(); + } + loadpkgdata(filename, pkg, p0, p1 - p0); + } + + // The __.PKGDEF archive summary has no local types. + if(whence == Pkgdef) + return; + + // local types begin where exports end. + // skip rest of line after $$ we found above + p0 = p1 + 3; + while(*p0 != '\n' && *p0 != '\0') + p0++; + + // local types end at next \n$$. + p1 = strstr(p0, "\n$$"); + if(p1 == nil) { + fprint(2, "%s: cannot find end of local types in %s\n", argv0, filename); + if(debug['u']) + errorexit(); + return; + } + + loadpkgdata(filename, pkg, p0, p1 - p0); + + // look for dynimport section + p0 = strstr(p1, "\n$$ // dynimport"); + if(p0 != nil) { + p0 = strchr(p0+1, '\n'); + if(p0 == nil) { + fprint(2, "%s: found $$ // dynimport but no newline in %s\n", argv0, filename); + if(debug['u']) + errorexit(); + return; + } + p1 = strstr(p0, "\n$$"); + if(p1 == nil) + p1 = strstr(p0, "\n!\n"); + if(p1 == nil) { + fprint(2, "%s: cannot find end of // dynimport section in %s\n", argv0, filename); + if(debug['u']) + errorexit(); + return; + } + loaddynimport(filename, pkg, p0 + 1, p1 - (p0+1)); + } + + // look for dynexp section + p0 = strstr(p1, "\n$$ // dynexport"); + if(p0 != nil) { + p0 = strchr(p0+1, '\n'); + if(p0 == nil) { + fprint(2, "%s: found $$ // dynexporg but no newline in %s\n", argv0, filename); + if(debug['u']) + errorexit(); + return; + } + p1 = strstr(p0, "\n$$"); + if(p1 == nil) + p1 = strstr(p0, "\n!\n"); + if(p1 == nil) { + fprint(2, "%s: cannot find end of // dynexporg section in %s\n", argv0, filename); + if(debug['u']) + errorexit(); + return; + } + loaddynexport(filename, pkg, p0 + 1, p1 - (p0+1)); + } +} + +static void +loadpkgdata(char *file, char *pkg, char *data, int len) +{ + char *p, *ep, *prefix, *name, *def; + Import *x; + + file = strdup(file); + p = data; + ep = data + len; + while(parsepkgdata(file, pkg, &p, ep, &prefix, &name, &def) > 0) { + x = ilookup(name); + if(x->prefix == nil) { + x->prefix = prefix; + x->def = def; + x->file = file; + } else if(strcmp(x->prefix, prefix) != 0) { + fprint(2, "%s: conflicting definitions for %s\n", argv0, name); + fprint(2, "%s:\t%s %s ...\n", x->file, x->prefix, name); + fprint(2, "%s:\t%s %s ...\n", file, prefix, name); + nerrors++; + } else if(strcmp(x->def, def) != 0) { + fprint(2, "%s: conflicting definitions for %s\n", argv0, name); + fprint(2, "%s:\t%s %s %s\n", x->file, x->prefix, name, x->def); + fprint(2, "%s:\t%s %s %s\n", file, prefix, name, def); + nerrors++; + } + } +} + +// replace all "". with pkg. +char* +expandpkg(char *t0, char *pkg) +{ + int n; + char *p; + char *w, *w0, *t; + + n = 0; + for(p=t0; (p=strstr(p, "\"\".")) != nil; p+=3) + n++; + + if(n == 0) + return t0; + + // use malloc, not mal, so that caller can free + w0 = malloc(strlen(t0) + strlen(pkg)*n); + if(w0 == nil) { + diag("out of memory"); + errorexit(); + } + w = w0; + for(p=t=t0; (p=strstr(p, "\"\".")) != nil; p=t) { + memmove(w, t, p - t); + w += p-t; + strcpy(w, pkg); + w += strlen(pkg); + t = p+2; + } + strcpy(w, t); + return w0; +} + +static int +parsepkgdata(char *file, char *pkg, char **pp, char *ep, char **prefixp, char **namep, char **defp) +{ + char *p, *prefix, *name, *def, *edef, *meth; + int n, inquote; + + // skip white space + p = *pp; +loop: + while(p < ep && (*p == ' ' || *p == '\t' || *p == '\n')) + p++; + if(p == ep || strncmp(p, "$$\n", 3) == 0) + return 0; + + // prefix: (var|type|func|const) + prefix = p; + if(p + 7 > ep) + return -1; + if(strncmp(p, "var ", 4) == 0) + p += 4; + else if(strncmp(p, "type ", 5) == 0) + p += 5; + else if(strncmp(p, "func ", 5) == 0) + p += 5; + else if(strncmp(p, "const ", 6) == 0) + p += 6; + else if(strncmp(p, "import ", 7) == 0) { + p += 7; + while(p < ep && *p != ' ') + p++; + p++; + name = p; + while(p < ep && *p != '\n') + p++; + if(p >= ep) { + fprint(2, "%s: %s: confused in import line\n", argv0, file); + nerrors++; + return -1; + } + *p++ = '\0'; + imported(pkg, name); + goto loop; + } + else { + fprint(2, "%s: %s: confused in pkg data near <<%.40s>>\n", argv0, file, prefix); + nerrors++; + return -1; + } + p[-1] = '\0'; + + // name: a.b followed by space + name = p; + inquote = 0; + while(p < ep) { + if (*p == ' ' && !inquote) + break; + + if(*p == '\\') + p++; + else if(*p == '"') + inquote = !inquote; + + p++; + } + + if(p >= ep) + return -1; + *p++ = '\0'; + + // def: free form to new line + def = p; + while(p < ep && *p != '\n') + p++; + if(p >= ep) + return -1; + edef = p; + *p++ = '\0'; + + // include methods on successive lines in def of named type + while(parsemethod(&p, ep, &meth) > 0) { + *edef++ = '\n'; // overwrites '\0' + if(edef+1 > meth) { + // We want to indent methods with a single \t. + // 6g puts at least one char of indent before all method defs, + // so there will be room for the \t. If the method def wasn't + // indented we could do something more complicated, + // but for now just diagnose the problem and assume + // 6g will keep indenting for us. + fprint(2, "%s: %s: expected methods to be indented %p %p %.10s\n", argv0, + file, edef, meth, meth); + nerrors++; + return -1; + } + *edef++ = '\t'; + n = strlen(meth); + memmove(edef, meth, n); + edef += n; + } + + name = expandpkg(name, pkg); + def = expandpkg(def, pkg); + + // done + *pp = p; + *prefixp = prefix; + *namep = name; + *defp = def; + return 1; +} + +static int +parsemethod(char **pp, char *ep, char **methp) +{ + char *p; + + // skip white space + p = *pp; + while(p < ep && (*p == ' ' || *p == '\t')) + p++; + if(p == ep) + return 0; + + // if it says "func (", it's a method + if(p + 6 >= ep || strncmp(p, "func (", 6) != 0) + return 0; + + // definition to end of line + *methp = p; + while(p < ep && *p != '\n') + p++; + if(p >= ep) { + fprint(2, "%s: lost end of line in method definition\n", argv0); + *pp = ep; + return -1; + } + *p++ = '\0'; + *pp = p; + return 1; +} + +static void +loaddynimport(char *file, char *pkg, char *p, int n) +{ + char *pend, *next, *name, *def, *p0, *lib, *q; + Sym *s; + + USED(file); + pend = p + n; + for(; ptype == 0 || s->type == SXREF) { + s->dynimplib = lib; + s->dynimpname = def; + s->dynimpvers = q; + s->type = SDYNIMPORT; + havedynamic = 1; + } + } + return; + +err: + fprint(2, "%s: %s: invalid dynimport line: %s\n", argv0, file, p0); + nerrors++; +} + +static void +loaddynexport(char *file, char *pkg, char *p, int n) +{ + char *pend, *next, *local, *elocal, *remote, *p0; + Sym *s; + + USED(file); + pend = p + n; + for(; pdynimplib != nil) { + fprint(2, "%s: symbol is both dynimport and dynexport %s\n", argv0, local); + nerrors++; + } + s->dynimpname = remote; + s->dynexport = 1; + + if(ndynexp%32 == 0) + dynexp = realloc(dynexp, (ndynexp+32)*sizeof dynexp[0]); + dynexp[ndynexp++] = s; + + if (elocal != local) + free(elocal); + } + return; + +err: + fprint(2, "%s: invalid dynexport line: %s\n", argv0, p0); + nerrors++; +} + +static int markdepth; + +static void +marktext(Sym *s) +{ + Auto *a; + Prog *p; + + if(s == S) + return; + markdepth++; + if(debug['v'] > 1) + Bprint(&bso, "%d marktext %s\n", markdepth, s->name); + for(a=s->autom; a; a=a->link) + mark(a->gotype); + for(p=s->text; p != P; p=p->link) { + if(p->from.sym) + mark(p->from.sym); + if(p->to.sym) + mark(p->to.sym); + } + markdepth--; +} + +void +mark(Sym *s) +{ + int i; + + if(s == S || s->reachable) + return; + if(strncmp(s->name, "weak.", 5) == 0) + return; + s->reachable = 1; + if(s->text) + marktext(s); + for(i=0; inr; i++) + mark(s->r[i].sym); + if(s->gotype) + mark(s->gotype); + if(s->sub) + mark(s->sub); + if(s->outer) + mark(s->outer); +} + +static char* +morename[] = +{ + "runtime.morestack", + "runtime.morestackx", + + "runtime.morestack00", + "runtime.morestack10", + "runtime.morestack01", + "runtime.morestack11", + + "runtime.morestack8", + "runtime.morestack16", + "runtime.morestack24", + "runtime.morestack32", + "runtime.morestack40", + "runtime.morestack48", +}; + +static int +isz(Auto *a) +{ + for(; a; a=a->link) + if(a->type == D_FILE || a->type == D_FILE1) + return 1; + return 0; +} + +static void +addz(Sym *s, Auto *z) +{ + Auto *a, *last; + + // strip out non-z + last = nil; + for(a = z; a != nil; a = a->link) { + if(a->type == D_FILE || a->type == D_FILE1) { + if(last == nil) + z = a; + else + last->link = a; + last = a; + } + } + if(last) { + last->link = s->autom; + s->autom = z; + } +} + +void +deadcode(void) +{ + int i; + Sym *s, *last; + Auto *z; + + if(debug['v']) + Bprint(&bso, "%5.2f deadcode\n", cputime()); + + mark(lookup(INITENTRY, 0)); + for(i=0; inext) { + if(!s->reachable) { + if(isz(s->autom)) + z = s->autom; + continue; + } + if(last == nil) + textp = s; + else + last->next = s; + last = s; + if(z != nil) { + if(!isz(s->autom)) + addz(s, z); + z = nil; + } + } + if(last == nil) + textp = nil; + else + last->next = nil; + + for(s = allsym; s != S; s = s->allsym) + if(strncmp(s->name, "weak.", 5) == 0) { + s->special = 1; // do not lay out in data segment + s->reachable = 1; + s->hide = 1; + } +} + +void +doweak(void) +{ + Sym *s, *t; + + // resolve weak references only if + // target symbol will be in binary anyway. + for(s = allsym; s != S; s = s->allsym) { + if(strncmp(s->name, "weak.", 5) == 0) { + t = rlookup(s->name+5, s->version); + if(t && t->type != 0 && t->reachable) { + s->value = t->value; + s->type = t->type; + } else { + s->type = SCONST; + s->value = 0; + } + continue; + } + } +} + +void +addexport(void) +{ + int i; + + for(i=0; iargs, char*); + if(s == nil) + return fmtstrcpy(fp, ""); + + se = s + strlen(s); + while(s < se) { + n = chartorune(&r, s); + s += n; + switch(r) { + case Runeerror: + if(n == 1) { + fmtprint(fp, "\\x%02x", (uchar)*(s-1)); + break; + } + // fall through + default: + if(r < ' ') { + fmtprint(fp, "\\x%02x", r); + break; + } + fmtrune(fp, r); + break; + case '\t': + fmtstrcpy(fp, "\\t"); + break; + case '\n': + fmtstrcpy(fp, "\\n"); + break; + case '\"': + case '\\': + fmtrune(fp, '\\'); + fmtrune(fp, r); + break; + } + } + return 0; +} + + +typedef struct Pkg Pkg; +struct Pkg +{ + uchar mark; + uchar checked; + Pkg *next; + char *path; + Pkg **impby; + int nimpby; + int mimpby; + Pkg *all; +}; + +static Pkg *phash[1024]; +static Pkg *pkgall; + +static Pkg* +getpkg(char *path) +{ + Pkg *p; + int h; + + h = hashstr(path) % nelem(phash); + for(p=phash[h]; p; p=p->next) + if(strcmp(p->path, path) == 0) + return p; + p = mal(sizeof *p); + p->path = strdup(path); + p->next = phash[h]; + phash[h] = p; + p->all = pkgall; + pkgall = p; + return p; +} + +static void +imported(char *pkg, char *import) +{ + Pkg *p, *i; + + // everyone imports runtime, even runtime. + if(strcmp(import, "\"runtime\"") == 0) + return; + + pkg = smprint("\"%Z\"", pkg); // turn pkg path into quoted form, freed below + p = getpkg(pkg); + i = getpkg(import); + if(i->nimpby >= i->mimpby) { + i->mimpby *= 2; + if(i->mimpby == 0) + i->mimpby = 16; + i->impby = realloc(i->impby, i->mimpby*sizeof i->impby[0]); + } + i->impby[i->nimpby++] = p; + free(pkg); +} + +static Pkg* +cycle(Pkg *p) +{ + int i; + Pkg *bad; + + if(p->checked) + return 0; + + if(p->mark) { + nerrors++; + print("import cycle:\n"); + print("\t%s\n", p->path); + return p; + } + p->mark = 1; + for(i=0; inimpby; i++) { + if((bad = cycle(p->impby[i])) != nil) { + p->mark = 0; + p->checked = 1; + print("\timports %s\n", p->path); + if(bad == p) + return nil; + return bad; + } + } + p->checked = 1; + p->mark = 0; + return 0; +} + +void +importcycles(void) +{ + Pkg *p; + + for(p=pkgall; p; p=p->all) + cycle(p); +} diff -r d8d00747375b sys/src/cmd/ld/ldelf.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/src/cmd/ld/ldelf.c Mon Nov 14 17:35:25 2011 +0100 @@ -0,0 +1,816 @@ +/* +Derived from Plan 9 from User Space's src/libmach/elf.h, elf.c +http://code.swtch.com/plan9port/src/tip/src/libmach/ + + Copyright © 2004 Russ Cox. + Portions Copyright © 2008-2010 Google Inc. + Portions Copyright © 2010 The Go Authors. + +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 "lib.h" +#include "../ld/elf.h" + +enum +{ + ElfClassNone = 0, + ElfClass32, + ElfClass64, + + ElfDataNone = 0, + ElfDataLsb, + ElfDataMsb, + + ElfTypeNone = 0, + ElfTypeRelocatable, + ElfTypeExecutable, + ElfTypeSharedObject, + ElfTypeCore, + /* 0xFF00 - 0xFFFF reserved for processor-specific types */ + + ElfMachNone = 0, + ElfMach32100, /* AT&T WE 32100 */ + ElfMachSparc, /* SPARC */ + ElfMach386, /* Intel 80386 */ + ElfMach68000, /* Motorola 68000 */ + ElfMach88000, /* Motorola 88000 */ + ElfMach486, /* Intel 80486, no longer used */ + ElfMach860, /* Intel 80860 */ + ElfMachMips, /* MIPS RS3000 */ + ElfMachS370, /* IBM System/370 */ + ElfMachMipsLe, /* MIPS RS3000 LE */ + ElfMachParisc = 15, /* HP PA RISC */ + ElfMachVpp500 = 17, /* Fujitsu VPP500 */ + ElfMachSparc32Plus, /* SPARC V8+ */ + ElfMach960, /* Intel 80960 */ + ElfMachPower, /* PowerPC */ + ElfMachPower64, /* PowerPC 64 */ + ElfMachS390, /* IBM System/390 */ + ElfMachV800 = 36, /* NEC V800 */ + ElfMachFr20, /* Fujitsu FR20 */ + ElfMachRh32, /* TRW RH-32 */ + ElfMachRce, /* Motorola RCE */ + ElfMachArm, /* ARM */ + ElfMachAlpha, /* Digital Alpha */ + ElfMachSH, /* Hitachi SH */ + ElfMachSparc9, /* SPARC V9 */ + ElfMachAmd64 = 62, + /* and the list goes on... */ + + ElfAbiNone = 0, + ElfAbiSystemV = 0, /* [sic] */ + ElfAbiHPUX, + ElfAbiNetBSD, + ElfAbiLinux, + ElfAbiSolaris = 6, + ElfAbiAix, + ElfAbiIrix, + ElfAbiFreeBSD, + ElfAbiTru64, + ElfAbiModesto, + ElfAbiOpenBSD, + ElfAbiARM = 97, + ElfAbiEmbedded = 255, + + /* some of sections 0xFF00 - 0xFFFF reserved for various things */ + ElfSectNone = 0, + ElfSectProgbits, + ElfSectSymtab, + ElfSectStrtab, + ElfSectRela, + ElfSectHash, + ElfSectDynamic, + ElfSectNote, + ElfSectNobits, + ElfSectRel, + ElfSectShlib, + ElfSectDynsym, + + ElfSectFlagWrite = 0x1, + ElfSectFlagAlloc = 0x2, + ElfSectFlagExec = 0x4, + /* 0xF0000000 are reserved for processor specific */ + + ElfSymBindLocal = 0, + ElfSymBindGlobal, + ElfSymBindWeak, + /* 13-15 reserved */ + + ElfSymTypeNone = 0, + ElfSymTypeObject, + ElfSymTypeFunc, + ElfSymTypeSection, + ElfSymTypeFile, + /* 13-15 reserved */ + + ElfSymShnNone = 0, + ElfSymShnAbs = 0xFFF1, + ElfSymShnCommon = 0xFFF2, + /* 0xFF00-0xFF1F reserved for processors */ + /* 0xFF20-0xFF3F reserved for operating systems */ + + ElfProgNone = 0, + ElfProgLoad, + ElfProgDynamic, + ElfProgInterp, + ElfProgNote, + ElfProgShlib, + ElfProgPhdr, + + ElfProgFlagExec = 0x1, + ElfProgFlagWrite = 0x2, + ElfProgFlagRead = 0x4, + + ElfNotePrStatus = 1, + ElfNotePrFpreg = 2, + ElfNotePrPsinfo = 3, + ElfNotePrTaskstruct = 4, + ElfNotePrAuxv = 6, + ElfNotePrXfpreg = 0x46e62b7f /* for gdb/386 */ +}; + +typedef struct ElfHdrBytes ElfHdrBytes; +typedef struct ElfSectBytes ElfSectBytes; +typedef struct ElfProgBytes ElfProgBytes; +typedef struct ElfSymBytes ElfSymBytes; + +typedef struct ElfHdrBytes64 ElfHdrBytes64; +typedef struct ElfSectBytes64 ElfSectBytes64; +typedef struct ElfProgBytes64 ElfProgBytes64; +typedef struct ElfSymBytes64 ElfSymBytes64; + +struct ElfHdrBytes +{ + uchar ident[16]; + uchar type[2]; + uchar machine[2]; + uchar version[4]; + uchar entry[4]; + uchar phoff[4]; + uchar shoff[4]; + uchar flags[4]; + uchar ehsize[2]; + uchar phentsize[2]; + uchar phnum[2]; + uchar shentsize[2]; + uchar shnum[2]; + uchar shstrndx[2]; +}; + +struct ElfHdrBytes64 +{ + uchar ident[16]; + uchar type[2]; + uchar machine[2]; + uchar version[4]; + uchar entry[8]; + uchar phoff[8]; + uchar shoff[8]; + uchar flags[4]; + uchar ehsize[2]; + uchar phentsize[2]; + uchar phnum[2]; + uchar shentsize[2]; + uchar shnum[2]; + uchar shstrndx[2]; +}; + +struct ElfSectBytes +{ + uchar name[4]; + uchar type[4]; + uchar flags[4]; + uchar addr[4]; + uchar off[4]; + uchar size[4]; + uchar link[4]; + uchar info[4]; + uchar align[4]; + uchar entsize[4]; +}; + +struct ElfSectBytes64 +{ + uchar name[4]; + uchar type[4]; + uchar flags[8]; + uchar addr[8]; + uchar off[8]; + uchar size[8]; + uchar link[4]; + uchar info[4]; + uchar align[8]; + uchar entsize[8]; +}; + +struct ElfSymBytes +{ + uchar name[4]; + uchar value[4]; + uchar size[4]; + uchar info; /* top4: bind, bottom4: type */ + uchar other; + uchar shndx[2]; +}; + +struct ElfSymBytes64 +{ + uchar name[4]; + uchar info; /* top4: bind, bottom4: type */ + uchar other; + uchar shndx[2]; + uchar value[8]; + uchar size[8]; +}; + +typedef struct ElfSect ElfSect; +typedef struct ElfObj ElfObj; +typedef struct ElfSym ElfSym; + +struct ElfSect +{ + char *name; + uint32 type; + uint64 flags; + uint64 addr; + uint64 off; + uint64 size; + uint32 link; + uint32 info; + uint64 align; + uint64 entsize; + uchar *base; + Sym *sym; +}; + +struct ElfObj +{ + Biobuf *f; + int64 base; // offset in f where ELF begins + int64 len; // length of ELF + int is64; + char *name; + + Endian *e; + ElfSect *sect; + uint nsect; + char *shstrtab; + int nsymtab; + ElfSect *symtab; + ElfSect *symstr; + + uint32 type; + uint32 machine; + uint32 version; + uint64 entry; + uint64 phoff; + uint64 shoff; + uint32 flags; + uint32 ehsize; + uint32 phentsize; + uint32 phnum; + uint32 shentsize; + uint32 shnum; + uint32 shstrndx; +}; + +struct ElfSym +{ + char* name; + uint64 value; + uint64 size; + uchar bind; + uchar type; + uchar other; + uint16 shndx; + Sym* sym; +}; + +uchar ElfMagic[4] = { 0x7F, 'E', 'L', 'F' }; + +static ElfSect* section(ElfObj*, char*); +static int map(ElfObj*, ElfSect*); +static int readsym(ElfObj*, int i, ElfSym*); +static int reltype(char*, int, uchar*); + +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; + Sym *s; + + USED(pkg); + if(debug['v']) + Bprint(&bso, "%5.2f ldelf %s\n", cputime(), pn); + + 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; insect; 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; insect; 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; insect; 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)", pn, sect->name); + s = lookup(name, 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 = SDATA; + break; + case ElfSectFlagAlloc + ElfSectFlagExec: + s->type = STEXT; + break; + } + if(sect->type == ElfSectProgbits) { + 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; + } + + // load relocations + for(i=0; insect; 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; joff = 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(readsym(obj, info>>32, &sym) < 0) + goto bad; + 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); + } + } + qsort(r, n, sizeof r[0], rbyoff); // just in case + + s = sect->sym; + s->r = r; + s->nr = n; + } + + // enter sub-symbols into symbol table. + // symbol 0 is the null symbol. + for(i=1; insymtab; i++) { + if(readsym(obj, i, &sym) < 0) + goto bad; + 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 = SBSS; + continue; + } + if(sym.shndx >= obj->nsect || sym.shndx == 0) + continue; + sect = obj->sect+sym.shndx; + if(sect->sym == nil) { + diag("%s: sym#%d: ignoring %s in section %d (type %d)", pn, i, sym.name, sym.shndx, sym.type); + continue; + } + s = sym.sym; + s->sub = sect->sym->sub; + sect->sym->sub = s; + s->type = sect->sym->type | SSUB; + if(!s->dynexport) { + s->dynimplib = nil; // satisfy dynimport + s->dynimpname = nil; // satisfy dynimport + } + s->value = sym.value; + s->size = sym.size; + 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 elf file: %r", pn); +} + +static ElfSect* +section(ElfObj *obj, char *name) +{ + int i; + + for(i=0; insect; i++) + if(obj->sect[i].name && name && strcmp(obj->sect[i].name, name) == 0) + return &obj->sect[i]; + return nil; +} + +static int +map(ElfObj *obj, ElfSect *sect) +{ + if(sect->base != nil) + return 0; + + if(sect->off+sect->size > obj->len) { + werrstr("elf section past end of file"); + return -1; + } + + sect->base = mal(sect->size); + werrstr("short read"); + if(Bseek(obj->f, obj->base+sect->off, 0) < 0 || Bread(obj->f, sect->base, sect->size) != sect->size) + return -1; + + return 0; +} + +static int +readsym(ElfObj *obj, int i, ElfSym *sym) +{ + Sym *s; + + if(i >= obj->nsymtab || i < 0) { + werrstr("invalid elf symbol index"); + return -1; + } + + if(obj->is64) { + ElfSymBytes64 *b; + + b = (ElfSymBytes64*)(obj->symtab->base + i*sizeof *b); + sym->name = (char*)obj->symstr->base + obj->e->e32(b->name); + sym->value = obj->e->e64(b->value); + sym->size = obj->e->e64(b->size); + sym->shndx = obj->e->e16(b->shndx); + sym->bind = b->info>>4; + sym->type = b->info&0xf; + sym->other = b->other; + } else { + ElfSymBytes *b; + + b = (ElfSymBytes*)(obj->symtab->base + i*sizeof *b); + sym->name = (char*)obj->symstr->base + obj->e->e32(b->name); + sym->value = obj->e->e32(b->value); + sym->size = obj->e->e32(b->size); + sym->shndx = obj->e->e16(b->shndx); + sym->bind = b->info>>4; + sym->type = b->info&0xf; + sym->other = b->other; + } + + s = nil; + if(strcmp(sym->name, "_GLOBAL_OFFSET_TABLE_") == 0) + sym->name = ".got"; + if(strcmp(sym->name, "__stack_chk_fail_local") == 0) + sym->other = 0; // rewrite hidden -> default visibility + switch(sym->type) { + case ElfSymTypeSection: + s = obj->sect[sym->shndx].sym; + break; + case ElfSymTypeObject: + case ElfSymTypeFunc: + case ElfSymTypeNone: + switch(sym->bind) { + case ElfSymBindGlobal: + if(sym->other != 2) { + s = lookup(sym->name, 0); + break; + } + // fall through + case ElfSymBindLocal: + s = lookup(sym->name, version); + break; + default: + werrstr("%s: invalid symbol binding %d", sym->name, sym->bind); + return -1; + } + break; + } + if(s != nil && s->type == 0 && sym->type != ElfSymTypeSection) + s->type = SXREF; + sym->sym = s; + + return 0; +} + +int +rbyoff(const void *va, const void *vb) +{ + Reloc *a, *b; + + a = (Reloc*)va; + b = (Reloc*)vb; + if(a->off < b->off) + return -1; + if(a->off > b->off) + return +1; + return 0; +} + +#define R(x, y) ((x)|((y)<<24)) + +static int +reltype(char *pn, int elftype, uchar *siz) +{ + switch(R(thechar, elftype)) { + default: + diag("%s: unknown relocation type %d; compiled without -fpic?", pn, elftype); + case R('6', R_X86_64_PC32): + case R('6', R_X86_64_PLT32): + case R('6', R_X86_64_GOTPCREL): + case R('8', R_386_32): + case R('8', R_386_PC32): + case R('8', R_386_GOT32): + case R('8', R_386_PLT32): + case R('8', R_386_GOTOFF): + case R('8', R_386_GOTPC): + *siz = 4; + break; + case R('6', R_X86_64_64): + *siz = 8; + break; + } + + return 256+elftype; +} diff -r d8d00747375b sys/src/cmd/ld/ldmacho.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/src/cmd/ld/ldmacho.c Mon Nov 14 17:35:25 2011 +0100 @@ -0,0 +1,821 @@ +/* +Derived from Plan 9 from User Space's src/libmach/elf.h, elf.c +http://code.swtch.com/plan9port/src/tip/src/libmach/ + + Copyright © 2004 Russ Cox. + Portions Copyright © 2008-2010 Google Inc. + Portions Copyright © 2010 The Go Authors. + +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 "lib.h" + +enum { + MACHO_FAKE_GOTPCREL = 100, // from macho.h + + N_EXT = 0x01, + N_TYPE = 0x1e, + N_STAB = 0xe0, +}; + +typedef struct MachoObj MachoObj; +typedef struct MachoCmd MachoCmd; +typedef struct MachoSeg MachoSeg; +typedef struct MachoSect MachoSect; +typedef struct MachoRel MachoRel; +typedef struct MachoSymtab MachoSymtab; +typedef struct MachoSym MachoSym; +typedef struct MachoDysymtab MachoDysymtab; + +enum +{ + MachoCpuVax = 1, + MachoCpu68000 = 6, + MachoCpu386 = 7, + MachoCpuAmd64 = 0x1000007, + MachoCpuMips = 8, + MachoCpu98000 = 10, + MachoCpuHppa = 11, + MachoCpuArm = 12, + MachoCpu88000 = 13, + MachoCpuSparc = 14, + MachoCpu860 = 15, + MachoCpuAlpha = 16, + MachoCpuPower = 18, + + MachoCmdSegment = 1, + MachoCmdSymtab = 2, + MachoCmdSymseg = 3, + MachoCmdThread = 4, + MachoCmdDysymtab = 11, + MachoCmdSegment64 = 25, + + MachoFileObject = 1, + MachoFileExecutable = 2, + MachoFileFvmlib = 3, + MachoFileCore = 4, + MachoFilePreload = 5, +}; + +struct MachoSeg +{ + char name[16+1]; + uint64 vmaddr; + uint64 vmsize; + uint32 fileoff; + uint32 filesz; + uint32 maxprot; + uint32 initprot; + uint32 nsect; + uint32 flags; + MachoSect *sect; +}; + +struct MachoSect +{ + char name[16+1]; + char segname[16+1]; + uint64 addr; + uint64 size; + uint32 off; + uint32 align; + uint32 reloff; + uint32 nreloc; + uint32 flags; + uint32 res1; + uint32 res2; + Sym *sym; + + MachoRel *rel; +}; + +struct MachoRel +{ + uint32 addr; + uint32 symnum; + uint8 pcrel; + uint8 length; + uint8 extrn; + uint8 type; + uint8 scattered; + uint32 value; +}; + +struct MachoSymtab +{ + uint32 symoff; + uint32 nsym; + uint32 stroff; + uint32 strsize; + + char *str; + MachoSym *sym; +}; + +struct MachoSym +{ + char *name; + uint8 type; + uint8 sectnum; + uint16 desc; + char kind; + uint64 value; + Sym *sym; +}; + +struct MachoDysymtab +{ + uint32 ilocalsym; + uint32 nlocalsym; + uint32 iextdefsym; + uint32 nextdefsym; + uint32 iundefsym; + uint32 nundefsym; + uint32 tocoff; + uint32 ntoc; + uint32 modtaboff; + uint32 nmodtab; + uint32 extrefsymoff; + uint32 nextrefsyms; + uint32 indirectsymoff; + uint32 nindirectsyms; + uint32 extreloff; + uint32 nextrel; + uint32 locreloff; + uint32 nlocrel; + uint32 *indir; +}; + +struct MachoCmd +{ + int type; + uint32 off; + uint32 size; + MachoSeg seg; + MachoSymtab sym; + MachoDysymtab dsym; +}; + +struct MachoObj +{ + Biobuf *f; + int64 base; // off in f where Mach-O begins + int64 len; // length of Mach-O + int is64; + char *name; + + Endian *e; + uint cputype; + uint subcputype; + uint32 filetype; + uint32 flags; + MachoCmd *cmd; + uint ncmd; +}; + +static int +unpackcmd(uchar *p, MachoObj *m, MachoCmd *c, uint type, uint sz) +{ + uint32 (*e4)(uchar*); + uint64 (*e8)(uchar*); + MachoSect *s; + int i; + + e4 = m->e->e32; + e8 = m->e->e64; + + c->type = type; + c->size = sz; + switch(type){ + default: + return -1; + case MachoCmdSegment: + if(sz < 56) + return -1; + strecpy(c->seg.name, c->seg.name+sizeof c->seg.name, (char*)p+8); + c->seg.vmaddr = e4(p+24); + c->seg.vmsize = e4(p+28); + c->seg.fileoff = e4(p+32); + c->seg.filesz = e4(p+36); + c->seg.maxprot = e4(p+40); + c->seg.initprot = e4(p+44); + c->seg.nsect = e4(p+48); + c->seg.flags = e4(p+52); + c->seg.sect = mal(c->seg.nsect * sizeof c->seg.sect[0]); + if(sz < 56+c->seg.nsect*68) + return -1; + p += 56; + for(i=0; iseg.nsect; i++) { + s = &c->seg.sect[i]; + strecpy(s->name, s->name+sizeof s->name, (char*)p+0); + strecpy(s->segname, s->segname+sizeof s->segname, (char*)p+16); + s->addr = e4(p+32); + s->size = e4(p+36); + s->off = e4(p+40); + s->align = e4(p+44); + s->reloff = e4(p+48); + s->nreloc = e4(p+52); + s->flags = e4(p+56); + s->res1 = e4(p+60); + s->res2 = e4(p+64); + p += 68; + } + break; + case MachoCmdSegment64: + if(sz < 72) + return -1; + strecpy(c->seg.name, c->seg.name+sizeof c->seg.name, (char*)p+8); + c->seg.vmaddr = e8(p+24); + c->seg.vmsize = e8(p+32); + c->seg.fileoff = e8(p+40); + c->seg.filesz = e8(p+48); + c->seg.maxprot = e4(p+56); + c->seg.initprot = e4(p+60); + c->seg.nsect = e4(p+64); + c->seg.flags = e4(p+68); + c->seg.sect = mal(c->seg.nsect * sizeof c->seg.sect[0]); + if(sz < 72+c->seg.nsect*80) + return -1; + p += 72; + for(i=0; iseg.nsect; i++) { + s = &c->seg.sect[i]; + strecpy(s->name, s->name+sizeof s->name, (char*)p+0); + strecpy(s->segname, s->segname+sizeof s->segname, (char*)p+16); + s->addr = e8(p+32); + s->size = e8(p+40); + s->off = e4(p+48); + s->align = e4(p+52); + s->reloff = e4(p+56); + s->nreloc = e4(p+60); + s->flags = e4(p+64); + s->res1 = e4(p+68); + s->res2 = e4(p+72); + // p+76 is reserved + p += 80; + } + break; + case MachoCmdSymtab: + if(sz < 24) + return -1; + c->sym.symoff = e4(p+8); + c->sym.nsym = e4(p+12); + c->sym.stroff = e4(p+16); + c->sym.strsize = e4(p+20); + break; + case MachoCmdDysymtab: + if(sz < 80) + return -1; + c->dsym.ilocalsym = e4(p+8); + c->dsym.nlocalsym = e4(p+12); + c->dsym.iextdefsym = e4(p+16); + c->dsym.nextdefsym = e4(p+20); + c->dsym.iundefsym = e4(p+24); + c->dsym.nundefsym = e4(p+28); + c->dsym.tocoff = e4(p+32); + c->dsym.ntoc = e4(p+36); + c->dsym.modtaboff = e4(p+40); + c->dsym.nmodtab = e4(p+44); + c->dsym.extrefsymoff = e4(p+48); + c->dsym.nextrefsyms = e4(p+52); + c->dsym.indirectsymoff = e4(p+56); + c->dsym.nindirectsyms = e4(p+60); + c->dsym.extreloff = e4(p+64); + c->dsym.nextrel = e4(p+68); + c->dsym.locreloff = e4(p+72); + c->dsym.nlocrel = e4(p+76); + break; + } + return 0; +} + +static int +macholoadrel(MachoObj *m, MachoSect *sect) +{ + MachoRel *rel, *r; + uchar *buf, *p; + int i, n; + uint32 v; + + if(sect->rel != nil || sect->nreloc == 0) + return 0; + rel = mal(sect->nreloc * sizeof r[0]); + n = sect->nreloc * 8; + buf = mal(n); + if(Bseek(m->f, m->base + sect->reloff, 0) < 0 || Bread(m->f, buf, n) != n) + return -1; + for(i=0; inreloc; i++) { + r = &rel[i]; + p = buf+i*8; + r->addr = m->e->e32(p); + + // TODO(rsc): Wrong interpretation for big-endian bitfields? + if(r->addr & 0x80000000) { + // scatterbrained relocation + r->scattered = 1; + v = r->addr >> 24; + r->addr &= 0xFFFFFF; + r->type = v & 0xF; + v >>= 4; + r->length = 1<<(v&3); + v >>= 2; + r->pcrel = v & 1; + r->value = m->e->e32(p+4); + } else { + v = m->e->e32(p+4); + r->symnum = v & 0xFFFFFF; + v >>= 24; + r->pcrel = v&1; + v >>= 1; + r->length = 1<<(v&3); + v >>= 2; + r->extrn = v&1; + v >>= 1; + r->type = v; + } + } + sect->rel = rel; + return 0; +} + +static int +macholoaddsym(MachoObj *m, MachoDysymtab *d) +{ + uchar *p; + int i, n; + + n = d->nindirectsyms; + + p = mal(n*4); + if(Bseek(m->f, m->base + d->indirectsymoff, 0) < 0 || Bread(m->f, p, n*4) != n*4) + return -1; + + d->indir = (uint32*)p; + for(i=0; iindir[i] = m->e->e32(p+4*i); + return 0; +} + +static int +macholoadsym(MachoObj *m, MachoSymtab *symtab) +{ + char *strbuf; + uchar *symbuf, *p; + int i, n, symsize; + MachoSym *sym, *s; + uint32 v; + + if(symtab->sym != nil) + return 0; + + strbuf = mal(symtab->strsize); + if(Bseek(m->f, m->base + symtab->stroff, 0) < 0 || Bread(m->f, strbuf, symtab->strsize) != symtab->strsize) + return -1; + + symsize = 12; + if(m->is64) + symsize = 16; + n = symtab->nsym * symsize; + symbuf = mal(n); + if(Bseek(m->f, m->base + symtab->symoff, 0) < 0 || Bread(m->f, symbuf, n) != n) + return -1; + sym = mal(symtab->nsym * sizeof sym[0]); + p = symbuf; + for(i=0; insym; i++) { + s = &sym[i]; + v = m->e->e32(p); + if(v >= symtab->strsize) + return -1; + s->name = strbuf + v; + s->type = p[4]; + s->sectnum = p[5]; + s->desc = m->e->e16(p+6); + if(m->is64) + s->value = m->e->e64(p+8); + else + s->value = m->e->e32(p+8); + p += symsize; + } + symtab->str = strbuf; + symtab->sym = sym; + return 0; +} + +void +ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) +{ + int i, j, is64; + uint64 secaddr; + uchar hdr[7*4], *cmdp; + uchar tmp[4]; + uchar *dat; + ulong ncmd, cmdsz, ty, sz, off; + MachoObj *m; + Endian *e; + int64 base; + MachoSect *sect; + MachoRel *rel; + Sym *s, *outer; + MachoCmd *c; + MachoSymtab *symtab; + MachoDysymtab *dsymtab; + MachoSym *sym; + Reloc *r, *rp; + char *name; + + USED(pkg); + version++; + base = Boffset(f); + if(Bread(f, hdr, sizeof hdr) != sizeof hdr) + goto bad; + + if((be.e32(hdr)&~1) == 0xFEEDFACE){ + e = &be; + }else if((le.e32(hdr)&~1) == 0xFEEDFACE){ + e = ≤ + }else{ + werrstr("bad magic - not mach-o file"); + goto bad; + } + + is64 = e->e32(hdr) == 0xFEEDFACF; + ncmd = e->e32(hdr+4*4); + cmdsz = e->e32(hdr+5*4); + if(ncmd > 0x10000 || cmdsz >= 0x01000000){ + werrstr("implausible mach-o header ncmd=%lud cmdsz=%lud", ncmd, cmdsz); + goto bad; + } + if(is64) + Bread(f, tmp, 4); // skip reserved word in header + + m = mal(sizeof(*m)+ncmd*sizeof(MachoCmd)+cmdsz); + m->f = f; + m->e = e; + m->cputype = e->e32(hdr+1*4); + m->subcputype = e->e32(hdr+2*4); + m->filetype = e->e32(hdr+3*4); + m->ncmd = ncmd; + m->flags = e->e32(hdr+6*4); + m->is64 = is64; + m->base = base; + m->len = len; + m->name = pn; + + switch(thechar) { + default: + diag("%s: mach-o %s unimplemented", pn, thestring); + return; + case '6': + if(e != &le || m->cputype != MachoCpuAmd64) { + diag("%s: mach-o object but not amd64", pn); + return; + } + break; + case '8': + if(e != &le || m->cputype != MachoCpu386) { + diag("%s: mach-o object but not 386", pn); + return; + } + break; + } + + m->cmd = (MachoCmd*)(m+1); + off = sizeof hdr; + cmdp = (uchar*)(m->cmd+ncmd); + if(Bread(f, cmdp, cmdsz) != cmdsz){ + werrstr("reading cmds: %r"); + goto bad; + } + + // read and parse load commands + c = nil; + symtab = nil; + dsymtab = nil; + for(i=0; ie32(cmdp); + sz = e->e32(cmdp+4); + m->cmd[i].off = off; + unpackcmd(cmdp, m, &m->cmd[i], ty, sz); + cmdp += sz; + off += sz; + if(ty == MachoCmdSymtab) { + if(symtab != nil) { + werrstr("multiple symbol tables"); + goto bad; + } + symtab = &m->cmd[i].sym; + macholoadsym(m, symtab); + } + if(ty == MachoCmdDysymtab) { + dsymtab = &m->cmd[i].dsym; + macholoaddsym(m, dsymtab); + } + if((is64 && ty == MachoCmdSegment64) || (!is64 && ty == MachoCmdSegment)) { + if(c != nil) { + werrstr("multiple load commands"); + goto bad; + } + c = &m->cmd[i]; + } + } + + // load text and data segments into memory. + // they are not as small as the load commands, but we'll need + // the memory anyway for the symbol images, so we might + // as well use one large chunk. + if(c == nil) { + werrstr("no load command"); + goto bad; + } + if(symtab == nil) { + // our work is done here - no symbols means nothing can refer to this file + return; + } + + if(c->seg.fileoff+c->seg.filesz >= len) { + werrstr("load segment out of range"); + goto bad; + } + + dat = mal(c->seg.filesz); + if(Bseek(f, m->base + c->seg.fileoff, 0) < 0 || Bread(f, dat, c->seg.filesz) != c->seg.filesz) { + werrstr("cannot load object data: %r"); + goto bad; + } + + for(i=0; iseg.nsect; i++) { + sect = &c->seg.sect[i]; + if(strcmp(sect->segname, "__TEXT") != 0 && strcmp(sect->segname, "__DATA") != 0) + continue; + if(strcmp(sect->name, "__eh_frame") == 0) + continue; + name = smprint("%s(%s/%s)", pn, sect->segname, sect->name); + s = lookup(name, version); + if(s->type != 0) { + werrstr("duplicate %s/%s", sect->segname, sect->name); + goto bad; + } + free(name); + s->p = dat + sect->addr - c->seg.vmaddr; + s->np = sect->size; + s->size = s->np; + + if(strcmp(sect->segname, "__TEXT") == 0) { + if(strcmp(sect->name, "__text") == 0) + s->type = STEXT; + else + s->type = SRODATA; + } else { + if (strcmp(sect->name, "__bss") == 0) { + s->type = SBSS; + s->np = 0; + } else + s->type = SDATA; + } + if(s->type == STEXT) { + if(etextp) + etextp->next = s; + else + textp = s; + etextp = s; + } + sect->sym = s; + } + + // enter sub-symbols into symbol table. + // have to guess sizes from next symbol. + for(i=0; insym; i++) { + int v; + sym = &symtab->sym[i]; + if(sym->type&N_STAB) + continue; + // TODO: check sym->type against outer->type. + name = sym->name; + if(name[0] == '_' && name[1] != '\0') + name++; + v = 0; + if(!(sym->type&N_EXT)) + v = version; + s = lookup(name, v); + sym->sym = s; + if(sym->sectnum == 0) // undefined + continue; + if(sym->sectnum > c->seg.nsect) { + werrstr("reference to invalid section %d", sym->sectnum); + goto bad; + } + sect = &c->seg.sect[sym->sectnum-1]; + outer = sect->sym; + if(outer == nil) { + werrstr("reference to invalid section %s/%s", sect->segname, sect->name); + continue; + } + s->type = outer->type | SSUB; + s->sub = outer->sub; + outer->sub = s; + s->outer = outer; + s->value = sym->value - sect->addr; + if(i+1 < symtab->nsym) + s->size = (sym+1)->value - sym->value; + else + s->size = sect->addr + sect->size - sym->value; + if(!s->dynexport) { + s->dynimplib = nil; // satisfy dynimport + s->dynimpname = nil; // satisfy dynimport + } + if(outer->type == STEXT) { + Prog *p; + + if(s->text != P) + diag("%s sym#%d: duplicate definition of %s", pn, i, s->name); + // build a TEXT instruction with a unique pc + // just to make the rest of the linker happy. + // TODO: this is too 6l-specific ? + 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; + } + sym->sym = s; + } + + // load relocations + for(i=0; iseg.nsect; i++) { + sect = &c->seg.sect[i]; + if((s = sect->sym) == S) + continue; + macholoadrel(m, sect); + if(sect->rel == nil) + continue; + r = mal(sect->nreloc*sizeof r[0]); + rp = r; + rel = sect->rel; + for(j=0; jnreloc; j++, rel++) { + if(rel->scattered) { + int k; + MachoSect *ks; + + if(thechar != '8') + diag("unexpected scattered relocation"); + + // on 386, rewrite scattered 4/1 relocation into + // the pseudo-pc-relative reference that it is. + // assume that the second in the pair is in this section + // and use that as the pc-relative base. + if(thechar != '8' || rel->type != 4 || j+1 >= sect->nreloc || + !(rel+1)->scattered || (rel+1)->type != 1 || + (rel+1)->value < sect->addr || (rel+1)->value >= sect->addr+sect->size) { + werrstr("unsupported scattered relocation %d/%d", (int)rel->type, (int)(rel+1)->type); + goto bad; + } + rp->siz = rel->length; + rp->off = rel->addr; + + // NOTE(rsc): I haven't worked out why (really when) + // we should ignore the addend on a + // scattered relocation, but it seems that the + // common case is we ignore it. + // It's likely that this is not strictly correct + // and that the math should look something + // like the non-scattered case below. + rp->add = 0; + + // want to make it pc-relative aka relative to rp->off+4 + // but the scatter asks for relative to off = (rel+1)->value - sect->addr. + // adjust rp->add accordingly. + rp->type = D_PCREL; + rp->add += (rp->off+4) - ((rel+1)->value - sect->addr); + + // now consider the desired symbol. + // find the section where it lives. + for(k=0; kseg.nsect; k++) { + ks = &c->seg.sect[k]; + if(ks->addr <= rel->value && rel->value < ks->addr+ks->size) + goto foundk; + } + werrstr("unsupported scattered relocation: invalid address %#ux", rel->addr); + goto bad; + foundk: + if(ks->sym != S) { + rp->sym = ks->sym; + rp->add += rel->value - ks->addr; + } else if(strcmp(ks->segname, "__IMPORT") == 0 && strcmp(ks->name, "__pointers") == 0) { + // handle reference to __IMPORT/__pointers. + // how much worse can this get? + // why are we supporting 386 on the mac anyway? + rp->type = 512 + MACHO_FAKE_GOTPCREL; + // figure out which pointer this is a reference to. + k = ks->res1 + (rel->value - ks->addr) / 4; + // load indirect table for __pointers + // fetch symbol number + if(dsymtab == nil || k < 0 || k >= dsymtab->nindirectsyms || dsymtab->indir == nil) { + werrstr("invalid scattered relocation: indirect symbol reference out of range"); + goto bad; + } + k = dsymtab->indir[k]; + if(k < 0 || k >= symtab->nsym) { + werrstr("invalid scattered relocation: symbol reference out of range"); + goto bad; + } + rp->sym = symtab->sym[k].sym; + } else { + werrstr("unsupported scattered relocation: reference to %s/%s", ks->segname, ks->name); + goto bad; + } + rp++; + // skip #1 of 2 rel; continue skips #2 of 2. + rel++; + j++; + continue; + } + + rp->siz = rel->length; + rp->type = 512 + (rel->type<<1) + rel->pcrel; + rp->off = rel->addr; + + // Handle X86_64_RELOC_SIGNED referencing a section (rel->extrn == 0). + if (thechar == '6' && rel->extrn == 0 && rel->type == 1) { + // Calculate the addend as the offset into the section. + // + // The rip-relative offset stored in the object file is encoded + // as follows: + // + // movsd 0x00000360(%rip),%xmm0 + // + // To get the absolute address of the value this rip-relative address is pointing + // to, we must add the address of the next instruction to it. This is done by + // taking the address of the relocation and adding 4 to it (since the rip-relative + // offset can at most be 32 bits long). To calculate the offset into the section the + // relocation is referencing, we subtract the vaddr of the start of the referenced + // section found in the original object file. + // + // [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h] + secaddr = c->seg.sect[rel->symnum-1].addr; + rp->add = e->e32(s->p+rp->off) + rp->off + 4 - secaddr; + } else + rp->add = e->e32(s->p+rp->off); + + // For i386 Mach-O PC-relative, the addend is written such that + // it *is* the PC being subtracted. Use that to make + // it match our version of PC-relative. + if(rel->pcrel && thechar == '8') + rp->add += rp->off+rp->siz; + if(!rel->extrn) { + if(rel->symnum < 1 || rel->symnum > c->seg.nsect) { + werrstr("invalid relocation: section reference out of range %d vs %d", rel->symnum, c->seg.nsect); + goto bad; + } + rp->sym = c->seg.sect[rel->symnum-1].sym; + if(rp->sym == nil) { + werrstr("invalid relocation: %s", c->seg.sect[rel->symnum-1].name); + goto bad; + } + // References to symbols in other sections + // include that information in the addend. + // We only care about the delta from the + // section base. + if(thechar == '8') + rp->add -= c->seg.sect[rel->symnum-1].addr; + } else { + if(rel->symnum >= symtab->nsym) { + werrstr("invalid relocation: symbol reference out of range"); + goto bad; + } + rp->sym = symtab->sym[rel->symnum].sym; + } + rp++; + } + qsort(r, rp - r, sizeof r[0], rbyoff); + s->r = r; + s->nr = rp - r; + } + return; + +bad: + diag("%s: malformed mach-o file: %r", pn); +} diff -r d8d00747375b sys/src/cmd/ld/ldpe.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/src/cmd/ld/ldpe.c Mon Nov 14 17:35:25 2011 +0100 @@ -0,0 +1,453 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "l.h" +#include "lib.h" +#include "../ld/pe.h" + +#define IMAGE_SCN_MEM_DISCARDABLE 0x2000000 + +#define IMAGE_SYM_UNDEFINED 0 +#define IMAGE_SYM_ABSOLUTE (-1) +#define IMAGE_SYM_DEBUG (-2) +#define IMAGE_SYM_TYPE_NULL 0 +#define IMAGE_SYM_TYPE_VOID 1 +#define IMAGE_SYM_TYPE_CHAR 2 +#define IMAGE_SYM_TYPE_SHORT 3 +#define IMAGE_SYM_TYPE_INT 4 +#define IMAGE_SYM_TYPE_LONG 5 +#define IMAGE_SYM_TYPE_FLOAT 6 +#define IMAGE_SYM_TYPE_DOUBLE 7 +#define IMAGE_SYM_TYPE_STRUCT 8 +#define IMAGE_SYM_TYPE_UNION 9 +#define IMAGE_SYM_TYPE_ENUM 10 +#define IMAGE_SYM_TYPE_MOE 11 +#define IMAGE_SYM_TYPE_BYTE 12 +#define IMAGE_SYM_TYPE_WORD 13 +#define IMAGE_SYM_TYPE_UINT 14 +#define IMAGE_SYM_TYPE_DWORD 15 +#define IMAGE_SYM_TYPE_PCODE 32768 +#define IMAGE_SYM_DTYPE_NULL 0 +#define IMAGE_SYM_DTYPE_POINTER 0x10 +#define IMAGE_SYM_DTYPE_FUNCTION 0x20 +#define IMAGE_SYM_DTYPE_ARRAY 0x30 +#define IMAGE_SYM_CLASS_END_OF_FUNCTION (-1) +#define IMAGE_SYM_CLASS_NULL 0 +#define IMAGE_SYM_CLASS_AUTOMATIC 1 +#define IMAGE_SYM_CLASS_EXTERNAL 2 +#define IMAGE_SYM_CLASS_STATIC 3 +#define IMAGE_SYM_CLASS_REGISTER 4 +#define IMAGE_SYM_CLASS_EXTERNAL_DEF 5 +#define IMAGE_SYM_CLASS_LABEL 6 +#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 7 +#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 8 +#define IMAGE_SYM_CLASS_ARGUMENT 9 +#define IMAGE_SYM_CLASS_STRUCT_TAG 10 +#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 11 +#define IMAGE_SYM_CLASS_UNION_TAG 12 +#define IMAGE_SYM_CLASS_TYPE_DEFINITION 13 +#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 14 +#define IMAGE_SYM_CLASS_ENUM_TAG 15 +#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 16 +#define IMAGE_SYM_CLASS_REGISTER_PARAM 17 +#define IMAGE_SYM_CLASS_BIT_FIELD 18 +#define IMAGE_SYM_CLASS_FAR_EXTERNAL 68 /* Not in PECOFF v8 spec */ +#define IMAGE_SYM_CLASS_BLOCK 100 +#define IMAGE_SYM_CLASS_FUNCTION 101 +#define IMAGE_SYM_CLASS_END_OF_STRUCT 102 +#define IMAGE_SYM_CLASS_FILE 103 +#define IMAGE_SYM_CLASS_SECTION 104 +#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 105 +#define IMAGE_SYM_CLASS_CLR_TOKEN 107 + +#define IMAGE_REL_I386_ABSOLUTE 0x0000 +#define IMAGE_REL_I386_DIR16 0x0001 +#define IMAGE_REL_I386_REL16 0x0002 +#define IMAGE_REL_I386_DIR32 0x0006 +#define IMAGE_REL_I386_DIR32NB 0x0007 +#define IMAGE_REL_I386_SEG12 0x0009 +#define IMAGE_REL_I386_SECTION 0x000A +#define IMAGE_REL_I386_SECREL 0x000B +#define IMAGE_REL_I386_TOKEN 0x000C +#define IMAGE_REL_I386_SECREL7 0x000D +#define IMAGE_REL_I386_REL32 0x0014 + +#define IMAGE_REL_AMD64_ABSOLUTE 0x0000 +#define IMAGE_REL_AMD64_ADDR64 0x0001 // R_X86_64_64 +#define IMAGE_REL_AMD64_ADDR32 0x0002 // R_X86_64_PC32 +#define IMAGE_REL_AMD64_ADDR32NB 0x0003 +#define IMAGE_REL_AMD64_REL32 0x0004 +#define IMAGE_REL_AMD64_REL32_1 0x0005 +#define IMAGE_REL_AMD64_REL32_2 0x0006 +#define IMAGE_REL_AMD64_REL32_3 0x0007 +#define IMAGE_REL_AMD64_REL32_4 0x0008 +#define IMAGE_REL_AMD64_REL32_5 0x0009 +#define IMAGE_REL_AMD64_SECTION 0x000A +#define IMAGE_REL_AMD64_SECREL 0x000B +#define IMAGE_REL_AMD64_SECREL7 0x000C +#define IMAGE_REL_AMD64_TOKEN 0x000D +#define IMAGE_REL_AMD64_SREL32 0x000E +#define IMAGE_REL_AMD64_PAIR 0x000F +#define IMAGE_REL_AMD64_SSPAN32 0x0010 + +typedef struct PeSym PeSym; +typedef struct PeSect PeSect; +typedef struct PeObj PeObj; + +struct PeSym { + char* name; + uint32 value; + uint16 sectnum; + uint16 type; + uint8 sclass; + uint8 aux; + Sym* sym; +}; + +struct PeSect { + char* name; + uchar* base; + uint64 size; + Sym* sym; + IMAGE_SECTION_HEADER sh; +}; + +struct PeObj { + Biobuf *f; + char *name; + uint32 base; + + PeSect *sect; + uint nsect; + PeSym *pesym; + uint npesym; + + IMAGE_FILE_HEADER fh; + char* snames; +}; + +static int map(PeObj *obj, PeSect *sect); +static int readsym(PeObj *obj, int i, PeSym **sym); + +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; ifh.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; insect; 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; insect; 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; jsh.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: + 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_ADDR32: // R_X86_64_PC32 + rp->type = D_PCREL; + rp->add += 4; + 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; inpesym; 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); +} + +static int +map(PeObj *obj, PeSect *sect) +{ + if(sect->base != nil) + return 0; + + sect->base = mal(sect->sh.SizeOfRawData); + if(sect->sh.PointerToRawData == 0) // .bss doesn't have data in object file + return 0; + werrstr("short read"); + if(Bseek(obj->f, obj->base+sect->sh.PointerToRawData, 0) < 0 || + Bread(obj->f, sect->base, sect->sh.SizeOfRawData) != sect->sh.SizeOfRawData) + return -1; + + return 0; +} + +static int +readsym(PeObj *obj, int i, PeSym **y) +{ + Sym *s; + PeSym *sym; + char *name, *p; + + if(i >= obj->npesym || i < 0) { + werrstr("invalid pe symbol index"); + return -1; + } + + sym = &obj->pesym[i]; + *y = sym; + + if(sym->name[0] == '.') // .section + name = obj->sect[sym->sectnum-1].sym->name; + else { + name = sym->name; + if(strncmp(name, "__imp_", 6) == 0) + name = &name[6]; // __imp_Name => Name + if(thechar == '8' && name[0] == '_') + name = &name[1]; // _Name => Name + } + // remove last @XXX + p = strchr(name, '@'); + if(p) + *p = 0; + + switch(sym->type) { + default: + werrstr("%s: invalid symbol type %d", sym->name, sym->type); + return -1; + case IMAGE_SYM_DTYPE_FUNCTION: + case IMAGE_SYM_DTYPE_NULL: + switch(sym->sclass) { + case IMAGE_SYM_CLASS_EXTERNAL: //global + s = lookup(name, 0); + break; + case IMAGE_SYM_CLASS_NULL: + case IMAGE_SYM_CLASS_STATIC: + s = lookup(name, version); + break; + default: + werrstr("%s: invalid symbol binding %d", sym->name, sym->sclass); + return -1; + } + break; + } + + if(s != nil && s->type == 0 && !(sym->sclass == IMAGE_SYM_CLASS_STATIC && sym->value == 0)) + s->type = SXREF; + if(strncmp(sym->name, "__imp_", 6) == 0) + s->got = -2; // flag for __imp_ + sym->sym = s; + + return 0; +} diff -r d8d00747375b sys/src/cmd/ld/lib.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/src/cmd/ld/lib.c Mon Nov 14 17:35:25 2011 +0100 @@ -0,0 +1,1458 @@ +// Derived from Inferno utils/6l/obj.c and utils/6l/span.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.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 "lib.h" +#include "../ld/stack.h" + +#include + +int iconv(Fmt*); + +char symname[] = SYMDEF; +char pkgname[] = "__.PKGDEF"; +char* libdir[16]; +int nlibdir = 0; +static int cout = -1; + +char* goroot; +char* goarch; +char* goos; +char* theline; + +void +Lflag(char *arg) +{ + if(nlibdir >= nelem(libdir)-1) { + print("too many -L's: %d\n", nlibdir); + usage(); + } + libdir[nlibdir++] = arg; +} + +void +libinit(void) +{ + fmtinstall('i', iconv); + fmtinstall('Y', Yconv); + fmtinstall('Z', Zconv); + mywhatsys(); // get goroot, goarch, goos + if(strcmp(goarch, thestring) != 0) + print("goarch is not known: %s\n", goarch); + + // add goroot to the end of the libdir list. + libdir[nlibdir++] = smprint("%s/pkg/%s_%s", goroot, goos, goarch); + + // Unix doesn't like it when we write to a running (or, sometimes, + // recently run) binary, so remove the output file before writing it. + // On Windows 7, remove() can force the following create() to fail. +#ifndef _WIN32 + remove(outfile); +#endif + cout = create(outfile, 1, 0775); + if(cout < 0) { + diag("cannot create %s", outfile); + errorexit(); + } + + if(INITENTRY == nil) { + INITENTRY = mal(strlen(goarch)+strlen(goos)+10); + sprint(INITENTRY, "_rt0_%s_%s", goarch, goos); + } + lookup(INITENTRY, 0)->type = SXREF; +} + +void +errorexit(void) +{ + if(nerrors) { + if(cout >= 0) + remove(outfile); + exits("error"); + } + exits(0); +} + +void +addlib(char *src, char *obj) +{ + char name[1024], pname[1024], comp[256], *p; + int i, search; + + if(histfrogp <= 0) + return; + + search = 0; + if(histfrog[0]->name[1] == '/') { + sprint(name, ""); + i = 1; + } else + if(isalpha(histfrog[0]->name[1]) && histfrog[0]->name[2] == ':') { + strcpy(name, histfrog[0]->name+1); + 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(name) + strlen(comp) + 3 >= sizeof(name)) { + diag("library component too long"); + return; + } + if(i > 0 || !search) + strcat(name, "/"); + strcat(name, comp); + } + cleanname(name); + + // runtime.a -> runtime + p = nil; + if(strlen(name) > 2 && name[strlen(name)-2] == '.') { + p = name+strlen(name)-2; + *p = '\0'; + } + + // already loaded? + for(i=0; i runtime.a for search + if(p != nil) + *p = '.'; + + if(search) { + // try dot, -L "libdir", and then goroot. + for(i=0; i= 0) + break; + } + }else + strcpy(pname, name); + cleanname(pname); + + /* runtime.a -> runtime */ + if(p != nil) + *p = '\0'; + + if(debug['v']) + Bprint(&bso, "%5.2f addlib: %s %s pulls in %s\n", cputime(), obj, src, pname); + + addlibpath(src, obj, pname, name); +} + +/* + * add library to library list. + * srcref: src file referring to package + * objref: object file referring to package + * file: object file, e.g., /home/rsc/go/pkg/container/vector.a + * pkg: package import path, e.g. container/vector + */ +void +addlibpath(char *srcref, char *objref, char *file, char *pkg) +{ + int i; + Library *l; + char *p; + + for(i=0; i 1) + Bprint(&bso, "%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s\n", + cputime(), srcref, objref, file, pkg); + + if(libraryp == nlibrary){ + nlibrary = 50 + 2*libraryp; + library = realloc(library, sizeof library[0] * nlibrary); + } + + l = &library[libraryp++]; + + p = mal(strlen(objref) + 1); + strcpy(p, objref); + l->objref = p; + + p = mal(strlen(srcref) + 1); + strcpy(p, srcref); + l->srcref = p; + + p = mal(strlen(file) + 1); + strcpy(p, file); + l->file = p; + + p = mal(strlen(pkg) + 1); + strcpy(p, pkg); + l->pkg = p; +} + +void +loadinternal(char *name) +{ + char pname[1024]; + int i, found; + + found = 0; + for(i=0; i= 0) { + addlibpath("internal", "internal", pname, name); + found = 1; + break; + } + } + if(!found) + Bprint(&bso, "warning: unable to find %s.a\n", name); +} + +void +loadlib(void) +{ + int i; + + loadinternal("runtime"); + if(thechar == '5') + loadinternal("math"); + + for(i=0; ifmag, ARFMAG, sizeof a->fmag)) + return -1; + arsize = strtol(a->size, 0, 0); + if (arsize&1) + arsize++; + return arsize + r; +} + +void +objfile(char *file, char *pkg) +{ + int32 off, l; + Biobuf *f; + char magbuf[SARMAG]; + char pname[150]; + struct ar_hdr arhdr; + + pkg = smprint("%i", pkg); + + if(debug['v']) + Bprint(&bso, "%5.2f ldobj: %s (%s)\n", cputime(), file, pkg); + Bflush(&bso); + f = Bopen(file, 0); + if(f == nil) { + diag("cannot open file: %s", file); + errorexit(); + } + l = Bread(f, magbuf, SARMAG); + if(l != SARMAG || strncmp(magbuf, ARMAG, SARMAG)){ + /* load it as a regular file */ + l = Bseek(f, 0L, 2); + Bseek(f, 0L, 0); + ldobj(f, pkg, l, file, FileObj); + Bterm(f); + return; + } + + /* skip over __.SYMDEF */ + off = Boffset(f); + if((l = nextar(f, off, &arhdr)) <= 0) { + 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; + } + off += l; + + /* skip over (or process) __.PKGDEF */ + if((l = nextar(f, off, &arhdr)) <= 0) { + diag("%s: short read on archive file symbol header", file); + goto out; + } + if(strncmp(arhdr.name, pkgname, strlen(pkgname))) { + diag("%s: second entry not package header", file); + goto out; + } + off += l; + + if(debug['u']) + ldpkg(f, pkg, atolwhex(arhdr.size), file, Pkgdef); + + /* + * load all the object files from the archive now. + * this gives us sequential file access and keeps us + * from needing to come back later to pick up more + * objects. it breaks the usual C archive model, but + * this is Go, not C. the common case in Go is that + * we need to load all the objects, and then we throw away + * the individual symbols that are unused. + * + * loading every object will also make it possible to + * load foreign objects not referenced by __.SYMDEF. + */ + for(;;) { + l = nextar(f, off, &arhdr); + if(l == 0) + break; + if(l < 0) { + diag("%s: malformed archive", file); + goto out; + } + off += l; + + l = SARNAME; + while(l > 0 && arhdr.name[l-1] == ' ') + l--; + snprint(pname, sizeof pname, "%s(%.*s)", file, utfnlen(arhdr.name, l), arhdr.name); + l = atolwhex(arhdr.size); + ldobj(f, pkg, l, pname, ArchiveObj); + } + +out: + Bterm(f); +} + +void +ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence) +{ + char *line; + int n, c1, c2, c3, c4; + uint32 magic; + vlong import0, import1, eof; + char *t; + + eof = Boffset(f) + len; + + pn = strdup(pn); + + c1 = Bgetc(f); + c2 = Bgetc(f); + c3 = Bgetc(f); + c4 = Bgetc(f); + Bungetc(f); + Bungetc(f); + Bungetc(f); + Bungetc(f); + + magic = c1<<24 | c2<<16 | c3<<8 | c4; + if(magic == 0x7f454c46) { // \x7F E L F + ldelf(f, pkg, len, pn); + return; + } + if((magic&~1) == 0xfeedface || (magic&~0x01000000) == 0xcefaedfe) { + ldmacho(f, pkg, len, pn); + return; + } + if(c1 == 0x4c && c2 == 0x01 || c1 == 0x64 && c2 == 0x86) { + ldpe(f, pkg, len, pn); + return; + } + + /* check the header */ + line = Brdline(f, '\n'); + if(line == nil) { + if(Blinelen(f) > 0) { + diag("%s: not an object file", pn); + return; + } + goto eof; + } + n = Blinelen(f) - 1; + line[n] = '\0'; + if(strncmp(line, "go object ", 10) != 0) { + if(strlen(pn) > 3 && strcmp(pn+strlen(pn)-3, ".go") == 0) { + print("%cl: input %s is not .%c file (use %cg to compile .go files)\n", thechar, pn, thechar, thechar); + errorexit(); + } + if(strcmp(line, thestring) == 0) { + // old header format: just $GOOS + diag("%s: stale object file", pn); + return; + } + diag("%s: not an object file", pn); + return; + } + + // First, check that the basic goos, string, and version match. + t = smprint("%s %s %s ", getgoos(), thestring, getgoversion()); + line[n] = ' '; + if(strncmp(line+10, t, strlen(t)) != 0 && !debug['f']) { + line[n] = '\0'; + diag("%s: object is [%s] expected [%s]", pn, line+10, t); + free(t); + return; + } + + // Second, check that longer lines match each other exactly, + // so that the Go compiler and write additional information + // that must be the same from run to run. + line[n] = '\0'; + if(n-10 > strlen(t)) { + if(theline == nil) + theline = strdup(line+10); + else if(strcmp(theline, line+10) != 0) { + line[n] = '\0'; + diag("%s: object is [%s] expected [%s]", pn, line+10, theline); + free(t); + return; + } + } + free(t); + line[n] = '\n'; + + /* skip over exports and other info -- ends with \n!\n */ + import0 = Boffset(f); + c1 = '\n'; // the last line ended in \n + c2 = Bgetc(f); + c3 = Bgetc(f); + while(c1 != '\n' || c2 != '!' || c3 != '\n') { + c1 = c2; + c2 = c3; + c3 = Bgetc(f); + if(c3 == Beof) + goto eof; + } + import1 = Boffset(f); + + Bseek(f, import0, 0); + ldpkg(f, pkg, import1 - import0 - 2, pn, whence); // -2 for !\n + Bseek(f, import1, 0); + + ldobj1(f, pkg, eof - Boffset(f), pn); + return; + +eof: + diag("truncated object file: %s", pn); +} + +static Sym* +_lookup(char *symb, int v, int creat) +{ + Sym *s; + char *p; + int32 h; + int l, c; + + h = v; + for(p=symb; c = *p; p++) + h = h+h+h + c; + l = (p - symb) + 1; + // not if(h < 0) h = ~h, because gcc 4.3 -O2 miscompiles it. + h &= 0xffffff; + h %= NHASH; + for(s = hash[h]; s != S; s = s->hash) + if(memcmp(s->name, symb, l) == 0) + return s; + if(!creat) + return nil; + + s = mal(sizeof(*s)); + if(debug['v'] > 1) + Bprint(&bso, "lookup %s\n", symb); + + s->dynid = -1; + s->plt = -1; + s->got = -1; + s->name = mal(l + 1); + memmove(s->name, symb, l); + + s->hash = hash[h]; + s->type = 0; + s->version = v; + s->value = 0; + s->sig = 0; + s->size = 0; + hash[h] = s; + nsymbol++; + + s->allsym = allsym; + allsym = s; + return s; +} + +Sym* +lookup(char *name, int v) +{ + return _lookup(name, v, 1); +} + +// read-only lookup +Sym* +rlookup(char *name, int v) +{ + return _lookup(name, v, 0); +} + +void +copyhistfrog(char *buf, int nbuf) +{ + char *p, *ep; + int i; + + p = buf; + ep = buf + nbuf; + for(i=0; iname+1); + if(i+1name = mal(2*(histfrogp+1) + 1); + + u->asym = s; + u->type = type; + u->aoffset = line; + u->link = curhist; + curhist = u; + + s->name[0] = 0; + j = 1; + for(i=0; ivalue; + s->name[j+0] = k>>8; + s->name[j+1] = k; + j += 2; + } + s->name[j] = 0; + s->name[j+1] = 0; +} + +void +histtoauto(void) +{ + Auto *l; + + while(l = curhist) { + 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; +} + +void +nuxiinit(void) +{ + int i, c; + + for(i=0; i<4; i++) { + c = find1(0x04030201L, i+1); + if(i < 2) + inuxi2[i] = c; + if(i < 1) + inuxi1[i] = c; + inuxi4[i] = c; + if(c == i) { + inuxi8[i] = c; + inuxi8[i+4] = c+4; + } else { + inuxi8[i] = c+4; + inuxi8[i+4] = c; + } + fnuxi4[i] = c; + fnuxi8[i] = c; + fnuxi8[i+4] = c+4; + } + if(debug['v']) { + Bprint(&bso, "inuxi = "); + for(i=0; i<1; i++) + Bprint(&bso, "%d", inuxi1[i]); + Bprint(&bso, " "); + for(i=0; i<2; i++) + Bprint(&bso, "%d", inuxi2[i]); + Bprint(&bso, " "); + for(i=0; i<4; i++) + Bprint(&bso, "%d", inuxi4[i]); + Bprint(&bso, " "); + for(i=0; i<8; i++) + Bprint(&bso, "%d", inuxi8[i]); + Bprint(&bso, "\nfnuxi = "); + for(i=0; i<4; i++) + Bprint(&bso, "%d", fnuxi4[i]); + Bprint(&bso, " "); + for(i=0; i<8; i++) + Bprint(&bso, "%d", fnuxi8[i]); + Bprint(&bso, "\n"); + } + Bflush(&bso); +} + +int +find1(int32 l, int c) +{ + char *p; + int i; + + p = (char*)&l; + for(i=0; i<4; i++) + if(*p++ == c) + return i; + return 0; +} + +int +find2(int32 l, int c) +{ + union { + int32 l; + short p[2]; + } u; + short *p; + int i; + + u.l = l; + p = u.p; + for(i=0; i<4; i+=2) { + if(((*p >> 8) & 0xff) == c) + return i; + if((*p++ & 0xff) == c) + return i+1; + } + return 0; +} + +int32 +ieeedtof(Ieee *e) +{ + int exp; + int32 v; + + if(e->h == 0) + return 0; + exp = (e->h>>20) & ((1L<<11)-1L); + exp -= (1L<<10) - 2L; + v = (e->h & 0xfffffL) << 3; + v |= (e->l >> 29) & 0x7L; + if((e->l >> 28) & 1) { + v++; + if(v & 0x800000L) { + v = (v & 0x7fffffL) >> 1; + exp++; + } + } + if(-148 <= exp && exp <= -126) { + v |= 1<<23; + v >>= -125 - exp; + exp = -126; + } + else if(exp < -148 || exp >= 130) + diag("double fp to single fp overflow: %.17g", ieeedtod(e)); + v |= ((exp + 126) & 0xffL) << 23; + v |= e->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; + exp = (ieeep->h>>20) & ((1L<<11)-1L); + exp -= (1L<<10) - 2L; + fr = ieeep->l & ((1L<<16)-1L); + fr /= 1L<<16; + fr += (ieeep->l>>16) & ((1L<<16)-1L); + fr /= 1L<<16; + if(exp == -(1L<<10) - 2L) { + fr += (ieeep->h & (1L<<20)-1L); + exp++; + } else + fr += (ieeep->h & (1L<<20)-1L) | (1L<<20); + fr /= 1L<<21; + return ldexp(fr, exp); +} + +void +zerosig(char *sp) +{ + Sym *s; + + s = lookup(sp, 0); + s->sig = 0; +} + +int32 +Bget4(Biobuf *f) +{ + uchar p[4]; + + if(Bread(f, p, 4) != 4) + return 0; + return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); +} + +void +mywhatsys(void) +{ + goroot = getgoroot(); + goos = getgoos(); + goarch = thestring; // ignore $GOARCH - we know who we are +} + +int +pathchar(void) +{ + return '/'; +} + +static uchar* hunk; +static uint32 nhunk; +#define NHUNK (10UL<<20) + +void* +mal(uint32 n) +{ + void *v; + + n = (n+7)&~7; + if(n > NHUNK) { + v = malloc(n); + if(v == nil) { + diag("out of memory"); + errorexit(); + } + memset(v, 0, n); + return v; + } + if(n > nhunk) { + hunk = malloc(NHUNK); + if(hunk == nil) { + diag("out of memory"); + errorexit(); + } + nhunk = NHUNK; + } + + v = hunk; + nhunk -= n; + hunk += n; + + memset(v, 0, n); + return v; +} + +void +unmal(void *v, uint32 n) +{ + n = (n+7)&~7; + if(hunk - n == v) { + hunk -= n; + nhunk += n; + } +} + +// Copied from ../gc/subr.c:/^pathtoprefix; must stay in sync. +/* + * Convert raw string to the prefix that will be used in the symbol table. + * Invalid bytes turn into %xx. Right now the only bytes that need + * escaping are %, ., and ", but we escape all control characters too. + * + * Must be same as ../gc/subr.c:/^pathtoprefix. + */ +static char* +pathtoprefix(char *s) +{ + static char hex[] = "0123456789abcdef"; + char *p, *r, *w, *l; + int n; + + // find first character past the last slash, if any. + l = s; + for(r=s; *r; r++) + if(*r == '/') + l = r+1; + + // check for chars that need escaping + n = 0; + for(r=s; *r; r++) + if(*r <= ' ' || (*r == '.' && r >= l) || *r == '%' || *r == '"' || *r >= 0x7f) + n++; + + // quick exit + if(n == 0) + return s; + + // escape + p = mal((r-s)+1+2*n); + for(r=s, w=p; *r; r++) { + if(*r <= ' ' || (*r == '.' && r >= l) || *r == '%' || *r == '"' || *r >= 0x7f) { + *w++ = '%'; + *w++ = hex[(*r>>4)&0xF]; + *w++ = hex[*r&0xF]; + } else + *w++ = *r; + } + *w = '\0'; + return p; +} + +int +iconv(Fmt *fp) +{ + char *p; + + p = va_arg(fp->args, char*); + if(p == nil) { + fmtstrcpy(fp, ""); + return 0; + } + p = pathtoprefix(p); + fmtstrcpy(fp, p); + return 0; +} + +void +mangle(char *file) +{ + fprint(2, "%s: mangled input file\n", file); + errorexit(); +} + +Section* +addsection(Segment *seg, char *name, int rwx) +{ + Section **l; + Section *sect; + + for(l=&seg->sect; *l; l=&(*l)->next) + ; + sect = mal(sizeof *sect); + sect->rwx = rwx; + sect->name = name; + sect->seg = seg; + *l = sect; + return sect; +} + +void +pclntab(void) +{ + vlong oldpc; + Prog *p; + int32 oldlc, v, s; + Sym *sym; + uchar *bp; + + sym = lookup("pclntab", 0); + sym->type = SPCLNTAB; + sym->reachable = 1; + if(debug['s']) + return; + + oldpc = INITTEXT; + oldlc = 0; + for(cursym = textp; cursym != nil; cursym = cursym->next) { + for(p = cursym->text; p != P; p = p->link) { + if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) { + if(debug['O']) + Bprint(&bso, "%6llux %P\n", + (vlong)p->pc, p); + continue; + } + if(debug['O']) + Bprint(&bso, "\t\t%6d", lcsize); + v = (p->pc - oldpc) / MINLC; + while(v) { + s = 127; + if(v < 127) + s = v; + symgrow(sym, lcsize+1); + bp = sym->p + lcsize; + *bp = s+128; /* 129-255 +pc */ + if(debug['O']) + Bprint(&bso, " pc+%d*%d(%d)", s, MINLC, s+128); + v -= s; + lcsize++; + } + s = p->line - oldlc; + oldlc = p->line; + oldpc = p->pc + MINLC; + if(s > 64 || s < -64) { + symgrow(sym, lcsize+5); + bp = sym->p + lcsize; + *bp++ = 0; /* 0 vv +lc */ + *bp++ = s>>24; + *bp++ = s>>16; + *bp++ = s>>8; + *bp = s; + if(debug['O']) { + if(s > 0) + Bprint(&bso, " lc+%d(%d,%d)\n", + s, 0, s); + else + Bprint(&bso, " lc%d(%d,%d)\n", + s, 0, s); + Bprint(&bso, "%6llux %P\n", + (vlong)p->pc, p); + } + lcsize += 5; + continue; + } + symgrow(sym, lcsize+1); + bp = sym->p + lcsize; + if(s > 0) { + *bp = 0+s; /* 1-64 +lc */ + if(debug['O']) { + Bprint(&bso, " lc+%d(%d)\n", s, 0+s); + Bprint(&bso, "%6llux %P\n", + (vlong)p->pc, p); + } + } else { + *bp = 64-s; /* 65-128 -lc */ + if(debug['O']) { + Bprint(&bso, " lc%d(%d)\n", s, 64-s); + Bprint(&bso, "%6llux %P\n", + (vlong)p->pc, p); + } + } + lcsize++; + } + } + if(lcsize & 1) { + symgrow(sym, lcsize+1); + sym->p[lcsize] = 129; + lcsize++; + } + sym->size = lcsize; + lcsize = 0; + + if(debug['v'] || debug['O']) + Bprint(&bso, "lcsize = %d\n", lcsize); + Bflush(&bso); +} + +#define LOG 5 +void +mkfwd(void) +{ + Prog *p; + int i; + int32 dwn[LOG], cnt[LOG]; + Prog *lst[LOG]; + + for(i=0; inext) { + for(p = cursym->text; p != P; p = p->link) { + if(p->link == P) { + if(cursym->next) + p->forwd = cursym->next->text; + break; + } + 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; + } + } + } +} + +uint16 +le16(uchar *b) +{ + return b[0] | b[1]<<8; +} + +uint32 +le32(uchar *b) +{ + return b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24; +} + +uint64 +le64(uchar *b) +{ + return le32(b) | (uint64)le32(b+4)<<32; +} + +uint16 +be16(uchar *b) +{ + return b[0]<<8 | b[1]; +} + +uint32 +be32(uchar *b) +{ + return b[0]<<24 | b[1]<<16 | b[2]<<8 | b[3]; +} + +uint64 +be64(uchar *b) +{ + return (uvlong)be32(b)<<32 | be32(b+4); +} + +Endian be = { be16, be32, be64 }; +Endian le = { le16, le32, le64 }; + +typedef struct Chain Chain; +struct Chain +{ + Sym *sym; + Chain *up; + int limit; // limit on entry to sym +}; + +static int stkcheck(Chain*, int); +static void stkprint(Chain*, int); +static void stkbroke(Chain*, int); +static Sym *morestack; +static Sym *newstack; + +enum +{ + HasLinkRegister = (thechar == '5'), + CallSize = (!HasLinkRegister)*PtrSize, // bytes of stack required for a call +}; + +void +dostkcheck(void) +{ + Chain ch; + Sym *s; + + morestack = lookup("runtime.morestack", 0); + newstack = lookup("runtime.newstack", 0); + + // First the nosplits on their own. + for(s = textp; s != nil; s = s->next) { + if(s->text == nil || s->text->link == nil || (s->text->textflag & NOSPLIT) == 0) + continue; + cursym = s; + ch.up = nil; + ch.sym = s; + ch.limit = StackLimit - CallSize; + stkcheck(&ch, 0); + s->stkcheck = 1; + } + + // Check calling contexts. + // Some nosplits get called a little further down, + // like newproc and deferproc. We could hard-code + // that knowledge but it's more robust to look at + // the actual call sites. + for(s = textp; s != nil; s = s->next) { + if(s->text == nil || s->text->link == nil || (s->text->textflag & NOSPLIT) != 0) + continue; + cursym = s; + ch.up = nil; + ch.sym = s; + ch.limit = StackLimit - CallSize; + stkcheck(&ch, 0); + } +} + +static int +stkcheck(Chain *up, int depth) +{ + Chain ch, ch1; + Prog *p; + Sym *s; + int limit, prolog; + + limit = up->limit; + s = up->sym; + p = s->text; + + // Small optimization: don't repeat work at top. + if(s->stkcheck && limit == StackLimit-CallSize) + return 0; + + if(depth > 100) { + diag("nosplit stack check too deep"); + stkbroke(up, 0); + return -1; + } + + if(p == nil || p->link == nil) { + // external function. + // should never be called directly. + // only diagnose the direct caller. + if(depth == 1) + diag("call to external function %s", s->name); + return -1; + } + + if(limit < 0) { + stkbroke(up, limit); + return -1; + } + + // morestack looks like it calls functions, + // but it switches the stack pointer first. + if(s == morestack) + return 0; + + ch.up = up; + prolog = (s->text->textflag & NOSPLIT) == 0; + for(p = s->text; p != P; p = p->link) { + limit -= p->spadj; + if(prolog && p->spadj != 0) { + // The first stack adjustment in a function with a + // split-checking prologue marks the end of the + // prologue. Assuming the split check is correct, + // after the adjustment there should still be at least + // StackLimit bytes available below the stack pointer. + // If this is not the top call in the chain, no need + // to duplicate effort, so just stop. + if(depth > 0) + return 0; + prolog = 0; + limit = StackLimit; + } + if(limit < 0) { + stkbroke(up, limit); + return -1; + } + if(iscall(p)) { + limit -= CallSize; + ch.limit = limit; + if(p->to.type == D_BRANCH) { + // Direct call. + ch.sym = p->to.sym; + if(stkcheck(&ch, depth+1) < 0) + return -1; + } else { + // Indirect call. Assume it is a splitting function, + // so we have to make sure it can call morestack. + limit -= CallSize; + ch.sym = nil; + ch1.limit = limit; + ch1.up = &ch; + ch1.sym = morestack; + if(stkcheck(&ch1, depth+2) < 0) + return -1; + limit += CallSize; + } + limit += CallSize; + } + + } + return 0; +} + +static void +stkbroke(Chain *ch, int limit) +{ + diag("nosplit stack overflow"); + stkprint(ch, limit); +} + +static void +stkprint(Chain *ch, int limit) +{ + char *name; + + if(ch->sym) + name = ch->sym->name; + else + name = "function pointer"; + + if(ch->up == nil) { + // top of chain. ch->sym != nil. + if(ch->sym->text->textflag & NOSPLIT) + print("\t%d\tassumed on entry to %s\n", ch->limit, name); + else + print("\t%d\tguaranteed after split check in %s\n", ch->limit, name); + } else { + stkprint(ch->up, ch->limit + (!HasLinkRegister)*PtrSize); + if(!HasLinkRegister) + print("\t%d\ton entry to %s\n", ch->limit, name); + } + if(ch->limit != limit) + print("\t%d\tafter %s uses %d\n", limit, name, ch->limit - limit); +} + +int +headtype(char *name) +{ + int i; + + for(i=0; headers[i].name; i++) + if(strcmp(name, headers[i].name) == 0) { + headstring = headers[i].name; + return headers[i].val; + } + fprint(2, "unknown header type -H %s\n", name); + errorexit(); + return -1; // not reached +} + +void +undef(void) +{ + Sym *s; + + for(s = allsym; s != S; s = s->allsym) + if(s->type == SXREF) + diag("%s(%d): not defined", s->name, s->version); +} + +int +Yconv(Fmt *fp) +{ + Sym *s; + Fmt fmt; + int i; + char *str; + + s = va_arg(fp->args, Sym*); + if (s == S) { + fmtprint(fp, ""); + } else { + fmtstrinit(&fmt); + fmtprint(&fmt, "%s @0x%08llx [%lld]", s->name, (vlong)s->value, (vlong)s->size); + for (i = 0; i < s->size; i++) { + if (!(i%8)) fmtprint(&fmt, "\n\t0x%04x ", i); + fmtprint(&fmt, "%02x ", s->p[i]); + } + fmtprint(&fmt, "\n"); + for (i = 0; i < s->nr; i++) { + fmtprint(&fmt, "\t0x%04x[%x] %d %s[%llx]\n", + s->r[i].off, + s->r[i].siz, + s->r[i].type, + s->r[i].sym->name, + (vlong)s->r[i].add); + } + str = fmtstrflush(&fmt); + fmtstrcpy(fp, str); + free(str); + } + + return 0; +} + +vlong coutpos; + +void +cflush(void) +{ + int n; + + if(cbpmax < cbp) + cbpmax = cbp; + n = cbpmax - buf.cbuf; + if(n) { + if(write(cout, buf.cbuf, n) != n) { + diag("write error: %r"); + errorexit(); + } + coutpos += n; + } + cbp = buf.cbuf; + cbc = sizeof(buf.cbuf); + cbpmax = cbp; +} + +vlong +cpos(void) +{ + return coutpos + cbp - buf.cbuf; +} + +void +cseek(vlong p) +{ + vlong start; + int delta; + + if(cbpmax < cbp) + cbpmax = cbp; + start = coutpos; + if(start <= p && p <= start+(cbpmax - buf.cbuf)) { +//print("cseek %lld in [%lld,%lld] (%lld)\n", p, start, start+sizeof(buf.cbuf), cpos()); + delta = p - (start + cbp - buf.cbuf); + cbp += delta; + cbc -= delta; +//print("now at %lld\n", cpos()); + return; + } + + cflush(); + seek(cout, p, 0); + coutpos = p; +} + +void +cwrite(void *buf, int n) +{ + cflush(); + if(write(cout, buf, n) != n) { + diag("write error: %r"); + errorexit(); + } + coutpos += n; +} diff -r d8d00747375b sys/src/cmd/ld/lib.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/src/cmd/ld/lib.h Mon Nov 14 17:35:25 2011 +0100 @@ -0,0 +1,309 @@ +// Derived from Inferno utils/6l/l.h +// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h +// +// 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. + +enum +{ + Sxxx, + + /* order here is order in output file */ + STEXT, + SMACHOPLT, + STYPE, + SSTRING, + SGOSTRING, + SRODATA, + SSYMTAB, + SPCLNTAB, + SELFROSECT, + SELFSECT, + SDATA, + SMACHO, /* Mach-O __nl_symbol_ptr */ + SMACHOGOT, + SWINDOWS, + SBSS, + + SXREF, + SMACHODYNSTR, + SMACHODYNSYM, + SMACHOINDIRECTPLT, + SMACHOINDIRECTGOT, + SFILE, + SCONST, + SDYNIMPORT, + + SSUB = 1<<8, /* sub-symbol, linked from parent via ->sub list */ + + NHASH = 100003, +}; + +typedef struct Library Library; +struct Library +{ + char *objref; // object where we found the reference + char *srcref; // src file where we found the reference + char *file; // object file + char *pkg; // import path +}; + +// Terrible but standard terminology. +// A segment describes a block of file to load into memory. +// A section further describes the pieces of that block for +// use in debuggers and such. + +typedef struct Segment Segment; +typedef struct Section Section; + +struct Segment +{ + uchar rwx; // permission as usual unix bits (5 = r-x etc) + uvlong vaddr; // virtual address + uvlong len; // length in memory + uvlong fileoff; // file offset + uvlong filelen; // length on disk + Section* sect; +}; + +struct Section +{ + uchar rwx; + char *name; + uvlong vaddr; + uvlong len; + Section *next; // in segment list + Segment *seg; +}; + +extern char symname[]; +extern char *libdir[]; +extern int nlibdir; + +EXTERN char* INITENTRY; +EXTERN char* thestring; +EXTERN Library* library; +EXTERN int libraryp; +EXTERN int nlibrary; +EXTERN Sym* hash[NHASH]; +EXTERN Sym* allsym; +EXTERN Sym* histfrog[MAXHIST]; +EXTERN uchar fnuxi8[8]; +EXTERN uchar fnuxi4[4]; +EXTERN int histfrogp; +EXTERN int histgen; +EXTERN uchar inuxi1[1]; +EXTERN uchar inuxi2[2]; +EXTERN uchar inuxi4[4]; +EXTERN uchar inuxi8[8]; +EXTERN char* outfile; +EXTERN int32 nsymbol; +EXTERN char* thestring; +EXTERN int ndynexp; +EXTERN int havedynamic; + +EXTERN Segment segtext; +EXTERN Segment segdata; +EXTERN Segment segsym; +EXTERN Segment segdwarf; + +void addlib(char *src, char *obj); +void addlibpath(char *srcref, char *objref, char *file, char *pkg); +Section* addsection(Segment*, char*, int); +void copyhistfrog(char *buf, int nbuf); +void addhist(int32 line, int type); +void asmlc(void); +void histtoauto(void); +void collapsefrog(Sym *s); +Sym* lookup(char *symb, int v); +Sym* rlookup(char *symb, int v); +void nuxiinit(void); +int find1(int32 l, int c); +int find2(int32 l, int c); +int32 ieeedtof(Ieee *e); +double ieeedtod(Ieee *e); +void undefsym(Sym *s); +void zerosig(char *sp); +void readundefs(char *f, int t); +int32 Bget4(Biobuf *f); +void loadlib(void); +void errorexit(void); +void mangle(char*); +void objfile(char *file, char *pkg); +void libinit(void); +void pclntab(void); +void symtab(void); +void Lflag(char *arg); +void usage(void); +void adddynrel(Sym*, Reloc*); +void ldobj1(Biobuf *f, char*, int64 len, char *pn); +void ldobj(Biobuf*, char*, int64, char*, int); +void ldelf(Biobuf*, char*, int64, char*); +void ldmacho(Biobuf*, char*, int64, char*); +void ldpe(Biobuf*, char*, int64, char*); +void ldpkg(Biobuf*, char*, int64, char*, int); +void mark(Sym *s); +void mkfwd(void); +char* expandpkg(char*, char*); +void deadcode(void); +Reloc* addrel(Sym*); +void codeblk(int32, int32); +void datblk(int32, int32); +Sym* datsort(Sym*); +void reloc(void); +void relocsym(Sym*); +void savedata(Sym*, Prog*, char*); +void symgrow(Sym*, int32); +vlong addstring(Sym*, char*); +vlong adduint32(Sym*, uint32); +vlong adduint64(Sym*, uint64); +vlong addaddr(Sym*, Sym*); +vlong addaddrplus(Sym*, Sym*, int32); +vlong addpcrelplus(Sym*, Sym*, int32); +vlong addsize(Sym*, Sym*); +vlong adduint8(Sym*, uint8); +vlong adduint16(Sym*, uint16); +void asmsym(void); +void asmelfsym(void); +void asmplan9sym(void); +void strnput(char*, int); +void dodata(void); +void address(void); +void textaddress(void); +void genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*)); +vlong datoff(vlong); +void adddynlib(char*); +int archreloc(Reloc*, Sym*, vlong*); +void adddynsym(Sym*); +void addexport(void); +void dostkcheck(void); +void undef(void); +void doweak(void); +void setpersrc(Sym*); + +int pathchar(void); +void* mal(uint32); +void unmal(void*, uint32); +void mywhatsys(void); +int rbyoff(const void*, const void*); + +uint16 le16(uchar*); +uint32 le32(uchar*); +uint64 le64(uchar*); +uint16 be16(uchar*); +uint32 be32(uchar*); +uint64 be64(uchar*); + +typedef struct Endian Endian; +struct Endian +{ + uint16 (*e16)(uchar*); + uint32 (*e32)(uchar*); + uint64 (*e64)(uchar*); +}; + +extern Endian be, le; + +// relocation size bits +enum { + Rbig = 128, + Rlittle = 64, +}; + +/* set by call to mywhatsys() */ +extern char* goroot; +extern char* goarch; +extern char* goos; + +/* whence for ldpkg */ +enum { + FileObj = 0, + ArchiveObj, + Pkgdef +}; + +/* executable header types */ +enum { + Hgarbunix = 0, // garbage unix + Hnoheader, // no header + Hunixcoff, // unix coff + Hrisc, // aif for risc os + Hplan9x32, // plan 9 32-bit format + Hplan9x64, // plan 9 64-bit format + Hmsdoscom, // MS-DOS .COM + Hnetbsd, // NetBSD + Hmsdosexe, // fake MS-DOS .EXE + Hixp1200, // IXP1200 (raw) + Helf, // ELF32 + Hipaq, // ipaq + Hdarwin, // Apple Mach-O + Hlinux, // Linux ELF + Hfreebsd, // FreeBSD ELF + Hwindows, // MS Windows PE + Hopenbsd, // OpenBSD ELF +}; + +typedef struct Header Header; +struct Header { + char *name; + int val; +}; + +EXTERN char* headstring; +extern Header headers[]; + +int headtype(char*); + +int Yconv(Fmt*); + +#pragma varargck type "O" int +#pragma varargck type "Y" Sym* + +// buffered output + +EXTERN Biobuf bso; + +EXTERN struct +{ + char cbuf[MAXIO]; /* output buffer */ +} buf; + +EXTERN int cbc; +EXTERN char* cbp; +EXTERN char* cbpmax; + +#define cput(c)\ + { *cbp++ = c;\ + if(--cbc <= 0)\ + cflush(); } + +void cflush(void); +vlong cpos(void); +void cseek(vlong); +void cwrite(void*, int); +void importcycles(void); +int Zconv(Fmt*); diff -r d8d00747375b sys/src/cmd/ld/macho.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/src/cmd/ld/macho.c Mon Nov 14 17:35:25 2011 +0100 @@ -0,0 +1,518 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Mach-O file writing +// http://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html + +#include "l.h" +#include "../ld/dwarf.h" +#include "../ld/lib.h" +#include "../ld/macho.h" + +static int macho64; +static MachoHdr hdr; +static MachoLoad *load; +static MachoSeg seg[16]; +static MachoDebug xdebug[16]; +static int nload, mload, nseg, ndebug, nsect; + +// Amount of space left for adding load commands +// that refer to dynamic libraries. Because these have +// to go in the Mach-O header, we can't just pick a +// "big enough" header size. The initial header is +// one page, the non-dynamic library stuff takes +// up about 1300 bytes; we overestimate that as 2k. +static int load_budget = INITIAL_MACHO_HEADR - 2*1024; + +void +machoinit(void) +{ + switch(thechar) { + // 64-bit architectures + case '6': + macho64 = 1; + break; + + // 32-bit architectures + default: + break; + } +} + +MachoHdr* +getMachoHdr(void) +{ + return &hdr; +} + +MachoLoad* +newMachoLoad(uint32 type, uint32 ndata) +{ + MachoLoad *l; + + if(nload >= mload) { + if(mload == 0) + mload = 1; + else + mload *= 2; + load = realloc(load, mload*sizeof load[0]); + if(load == nil) { + diag("out of memory"); + errorexit(); + } + } + + if(macho64 && (ndata & 1)) + ndata++; + + l = &load[nload++]; + l->type = type; + l->ndata = ndata; + l->data = mal(ndata*4); + return l; +} + +MachoSeg* +newMachoSeg(char *name, int msect) +{ + MachoSeg *s; + + if(nseg >= nelem(seg)) { + diag("too many segs"); + errorexit(); + } + s = &seg[nseg++]; + s->name = name; + s->msect = msect; + s->sect = mal(msect*sizeof s->sect[0]); + return s; +} + +MachoSect* +newMachoSect(MachoSeg *seg, char *name) +{ + MachoSect *s; + + if(seg->nsect >= seg->msect) { + diag("too many sects in segment %s", seg->name); + errorexit(); + } + s = &seg->sect[seg->nsect++]; + s->name = name; + nsect++; + return s; +} + +MachoDebug* +newMachoDebug(void) +{ + if(ndebug >= nelem(xdebug)) { + diag("too many debugs"); + errorexit(); + } + return &xdebug[ndebug++]; +} + + +// Generic linking code. + +static char **dylib; +static int ndylib; + +static vlong linkoff; + +int +machowrite(void) +{ + vlong o1; + int loadsize; + int i, j; + MachoSeg *s; + MachoSect *t; + MachoDebug *d; + MachoLoad *l; + + o1 = cpos(); + + loadsize = 4*4*ndebug; + for(i=0; insect); + strnput(s->name, 16); + VPUT(s->vaddr); + VPUT(s->vsize); + VPUT(s->fileoffset); + VPUT(s->filesize); + LPUT(s->prot1); + LPUT(s->prot2); + LPUT(s->nsect); + LPUT(s->flag); + } else { + LPUT(1); /* segment 32 */ + LPUT(56+68*s->nsect); + strnput(s->name, 16); + LPUT(s->vaddr); + LPUT(s->vsize); + LPUT(s->fileoffset); + LPUT(s->filesize); + LPUT(s->prot1); + LPUT(s->prot2); + LPUT(s->nsect); + LPUT(s->flag); + } + for(j=0; jnsect; j++) { + t = &s->sect[j]; + if(macho64) { + strnput(t->name, 16); + strnput(s->name, 16); + VPUT(t->addr); + VPUT(t->size); + LPUT(t->off); + LPUT(t->align); + LPUT(t->reloc); + LPUT(t->nreloc); + LPUT(t->flag); + LPUT(t->res1); /* reserved */ + LPUT(t->res2); /* reserved */ + LPUT(0); /* reserved */ + } else { + strnput(t->name, 16); + strnput(s->name, 16); + LPUT(t->addr); + LPUT(t->size); + LPUT(t->off); + LPUT(t->align); + LPUT(t->reloc); + LPUT(t->nreloc); + LPUT(t->flag); + LPUT(t->res1); /* reserved */ + LPUT(t->res2); /* reserved */ + } + } + } + + for(i=0; itype); + LPUT(4*(l->ndata+2)); + for(j=0; jndata; j++) + LPUT(l->data[j]); + } + + for(i=0; ifileoffset); + LPUT(d->filesize); + } + + return cpos() - o1; +} + +void +domacho(void) +{ + Sym *s; + + if(debug['d']) + return; + + // empirically, string table must begin with " \x00". + s = lookup(".dynstr", 0); + s->type = SMACHODYNSTR; + s->reachable = 1; + adduint8(s, ' '); + adduint8(s, '\0'); + + s = lookup(".dynsym", 0); + s->type = SMACHODYNSYM; + s->reachable = 1; + + s = lookup(".plt", 0); // will be __symbol_stub + s->type = SMACHOPLT; + s->reachable = 1; + + s = lookup(".got", 0); // will be __nl_symbol_ptr + s->type = SMACHOGOT; + s->reachable = 1; + + s = lookup(".linkedit.plt", 0); // indirect table for .plt + s->type = SMACHOINDIRECTPLT; + s->reachable = 1; + + s = lookup(".linkedit.got", 0); // indirect table for .got + s->type = SMACHOINDIRECTGOT; + s->reachable = 1; +} + +void +machoadddynlib(char *lib) +{ + // Will need to store the library name rounded up + // and 24 bytes of header metadata. If not enough + // space, grab another page of initial space at the + // beginning of the output file. + load_budget -= (strlen(lib)+7)/8*8 + 24; + if(load_budget < 0) { + HEADR += 4096; + INITTEXT += 4096; + load_budget += 4096; + } + + if(ndylib%32 == 0) { + dylib = realloc(dylib, (ndylib+32)*sizeof dylib[0]); + if(dylib == nil) { + diag("out of memory"); + errorexit(); + } + } + dylib[ndylib++] = lib; +} + +void +asmbmacho(void) +{ + vlong v, w; + vlong va; + int a, i; + MachoHdr *mh; + MachoSect *msect; + MachoSeg *ms; + MachoDebug *md; + MachoLoad *ml; + Sym *s; + + /* apple MACH */ + va = INITTEXT - HEADR; + mh = getMachoHdr(); + switch(thechar){ + default: + diag("unknown mach architecture"); + errorexit(); + case '6': + mh->cpu = MACHO_CPU_AMD64; + mh->subcpu = MACHO_SUBCPU_X86; + break; + case '8': + mh->cpu = MACHO_CPU_386; + mh->subcpu = MACHO_SUBCPU_X86; + break; + } + + /* segment for zero page */ + ms = newMachoSeg("__PAGEZERO", 0); + ms->vsize = va; + + /* text */ + v = rnd(HEADR+segtext.len, INITRND); + ms = newMachoSeg("__TEXT", 2); + ms->vaddr = va; + ms->vsize = v; + ms->filesize = v; + ms->prot1 = 7; + ms->prot2 = 5; + + msect = newMachoSect(ms, "__text"); + msect->addr = INITTEXT; + msect->size = segtext.sect->len; + msect->off = INITTEXT - va; + msect->flag = 0x400; /* flag - some instructions */ + + s = lookup(".plt", 0); + if(s->size > 0) { + msect = newMachoSect(ms, "__symbol_stub1"); + msect->addr = symaddr(s); + msect->size = s->size; + msect->off = ms->fileoffset + msect->addr - ms->vaddr; + msect->flag = 0x80000408; /* flag */ + msect->res1 = 0; /* index into indirect symbol table */ + msect->res2 = 6; /* size of stubs */ + } + + /* data */ + w = segdata.len; + ms = newMachoSeg("__DATA", 3); + ms->vaddr = va+v; + ms->vsize = w; + ms->fileoffset = v; + ms->filesize = segdata.filelen; + ms->prot1 = 7; + ms->prot2 = 3; + + msect = newMachoSect(ms, "__data"); + msect->addr = va+v; + msect->off = v; + msect->size = segdata.filelen; + + s = lookup(".got", 0); + if(s->size > 0) { + msect->size = symaddr(s) - msect->addr; + + msect = newMachoSect(ms, "__nl_symbol_ptr"); + msect->addr = symaddr(s); + msect->size = s->size; + msect->off = datoff(msect->addr); + msect->align = 2; + msect->flag = 6; /* section with nonlazy symbol pointers */ + msect->res1 = lookup(".linkedit.plt", 0)->size / 4; /* offset into indirect symbol table */ + } + + msect = newMachoSect(ms, "__bss"); + msect->addr = va+v+segdata.filelen; + msect->size = segdata.len - segdata.filelen; + msect->flag = 1; /* flag - zero fill */ + + switch(thechar) { + default: + diag("unknown macho architecture"); + errorexit(); + case '6': + ml = newMachoLoad(5, 42+2); /* unix thread */ + ml->data[0] = 4; /* thread type */ + ml->data[1] = 42; /* word count */ + ml->data[2+32] = entryvalue(); /* start pc */ + ml->data[2+32+1] = entryvalue()>>16>>16; // hide >>32 for 8l + break; + case '8': + ml = newMachoLoad(5, 16+2); /* unix thread */ + ml->data[0] = 1; /* thread type */ + ml->data[1] = 16; /* word count */ + ml->data[2+10] = entryvalue(); /* start pc */ + break; + } + + if(!debug['d']) { + Sym *s1, *s2, *s3, *s4; + + // must match domacholink below + s1 = lookup(".dynsym", 0); + s2 = lookup(".linkedit.plt", 0); + s3 = lookup(".linkedit.got", 0); + s4 = lookup(".dynstr", 0); + + ms = newMachoSeg("__LINKEDIT", 0); + ms->vaddr = va+v+rnd(segdata.len, INITRND); + ms->vsize = s1->size + s2->size + s3->size + s4->size; + ms->fileoffset = linkoff; + ms->filesize = ms->vsize; + ms->prot1 = 7; + ms->prot2 = 3; + + ml = newMachoLoad(2, 4); /* LC_SYMTAB */ + ml->data[0] = linkoff; /* symoff */ + ml->data[1] = s1->size / (macho64 ? 16 : 12); /* nsyms */ + ml->data[2] = linkoff + s1->size + s2->size + s3->size; /* stroff */ + ml->data[3] = s4->size; /* strsize */ + + ml = newMachoLoad(11, 18); /* LC_DYSYMTAB */ + ml->data[0] = 0; /* ilocalsym */ + ml->data[1] = 0; /* nlocalsym */ + ml->data[2] = 0; /* iextdefsym */ + ml->data[3] = ndynexp; /* nextdefsym */ + ml->data[4] = ndynexp; /* iundefsym */ + ml->data[5] = (s1->size / (macho64 ? 16 : 12)) - ndynexp; /* nundefsym */ + ml->data[6] = 0; /* tocoffset */ + ml->data[7] = 0; /* ntoc */ + ml->data[8] = 0; /* modtaboff */ + ml->data[9] = 0; /* nmodtab */ + ml->data[10] = 0; /* extrefsymoff */ + ml->data[11] = 0; /* nextrefsyms */ + ml->data[12] = linkoff + s1->size; /* indirectsymoff */ + ml->data[13] = (s2->size + s3->size) / 4; /* nindirectsyms */ + ml->data[14] = 0; /* extreloff */ + ml->data[15] = 0; /* nextrel */ + ml->data[16] = 0; /* locreloff */ + ml->data[17] = 0; /* nlocrel */ + + ml = newMachoLoad(14, 6); /* LC_LOAD_DYLINKER */ + ml->data[0] = 12; /* offset to string */ + strcpy((char*)&ml->data[1], "/usr/lib/dyld"); + + for(i=0; idata[0] = 24; /* offset of string from beginning of load */ + ml->data[1] = 0; /* time stamp */ + ml->data[2] = 0; /* version */ + ml->data[3] = 0; /* compatibility version */ + strcpy((char*)&ml->data[4], dylib[i]); + } + } + + if(!debug['s']) { + Sym *s; + + md = newMachoDebug(); + s = lookup("symtab", 0); + md->fileoffset = datoff(s->value); + md->filesize = s->size; + + md = newMachoDebug(); + s = lookup("pclntab", 0); + md->fileoffset = datoff(s->value); + md->filesize = s->size; + + dwarfaddmachoheaders(); + } + + a = machowrite(); + if(a > HEADR) + diag("HEADR too small: %d > %d", a, HEADR); +} + +vlong +domacholink(void) +{ + int size; + Sym *s1, *s2, *s3, *s4; + + // write data that will be linkedit section + s1 = lookup(".dynsym", 0); + relocsym(s1); + s2 = lookup(".linkedit.plt", 0); + s3 = lookup(".linkedit.got", 0); + s4 = lookup(".dynstr", 0); + + while(s4->size%4) + adduint8(s4, 0); + + size = s1->size + s2->size + s3->size + s4->size; + + if(size > 0) { + linkoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen, INITRND) + rnd(segdwarf.filelen, INITRND); + cseek(linkoff); + + cwrite(s1->p, s1->size); + cwrite(s2->p, s2->size); + cwrite(s3->p, s3->size); + cwrite(s4->p, s4->size); + } + + return rnd(size, INITRND); +} diff -r d8d00747375b sys/src/cmd/ld/macho.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/src/cmd/ld/macho.h Mon Nov 14 17:35:25 2011 +0100 @@ -0,0 +1,94 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +typedef struct MachoHdr MachoHdr; +struct MachoHdr { + uint32 cpu; + uint32 subcpu; +}; + +typedef struct MachoSect MachoSect; +struct MachoSect { + char* name; + uint64 addr; + uint64 size; + uint32 off; + uint32 align; + uint32 reloc; + uint32 nreloc; + uint32 flag; + uint32 res1; + uint32 res2; +}; + +typedef struct MachoSeg MachoSeg; +struct MachoSeg { + char* name; + uint64 vsize; + uint64 vaddr; + uint64 fileoffset; + uint64 filesize; + uint32 prot1; + uint32 prot2; + uint32 nsect; + uint32 msect; + MachoSect *sect; + uint32 flag; +}; + +typedef struct MachoLoad MachoLoad; +struct MachoLoad { + uint32 type; + uint32 ndata; + uint32 *data; +}; + +typedef struct MachoDebug MachoDebug; +struct MachoDebug { + uint32 fileoffset; + uint32 filesize; +}; + +MachoHdr* getMachoHdr(); +MachoSeg* newMachoSeg(char*, int); +MachoSect* newMachoSect(MachoSeg*, char*); +MachoLoad* newMachoLoad(uint32, uint32); +MachoDebug* newMachoDebug(void); +int machowrite(void); +void machoinit(void); + +/* + * Total amount of space to reserve at the start of the file + * for Header, PHeaders, and SHeaders. + * May waste some. + */ +#define INITIAL_MACHO_HEADR 4*1024 + +enum { + MACHO_CPU_AMD64 = (1<<24)|7, + MACHO_CPU_386 = 7, + MACHO_SUBCPU_X86 = 3, + + MACHO32SYMSIZE = 12, + MACHO64SYMSIZE = 16, + + MACHO_X86_64_RELOC_UNSIGNED = 0, + MACHO_X86_64_RELOC_SIGNED = 1, + MACHO_X86_64_RELOC_BRANCH = 2, + MACHO_X86_64_RELOC_GOT_LOAD = 3, + MACHO_X86_64_RELOC_GOT = 4, + MACHO_X86_64_RELOC_SUBTRACTOR = 5, + MACHO_X86_64_RELOC_SIGNED_1 = 6, + MACHO_X86_64_RELOC_SIGNED_2 = 7, + MACHO_X86_64_RELOC_SIGNED_4 = 8, + + MACHO_GENERIC_RELOC_VANILLA = 0, + + MACHO_FAKE_GOTPCREL = 100, +}; + +void domacho(void); +vlong domacholink(void); +void asmbmacho(void); +void machoadddynlib(char*); diff -r d8d00747375b sys/src/cmd/ld/mkfile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/src/cmd/ld/mkfile Mon Nov 14 17:35:25 2011 +0100 @@ -0,0 +1,35 @@ +data.$O: ../ld/data.c + $CC $CFLAGS ../ld/data.c + +dwarf.$O: ../ld/dwarf.c + $CC $CFLAGS ../ld/dwarf.c + +elf.$O: ../ld/elf.c + $CC $CFLAGS ../ld/elf.c + +elf.$O: ../ld/elf.c + $CC $CFLAGS ../ld/elf.c + +go.$O: ../ld/go.c + $CC $CFLAGS ../ld/go.c + +ldelf.$O: ../ld/ldelf.c + $CC $CFLAGS ../ld/ldelf.c + +ldmacho.$O: ../ld/ldmacho.c + $CC $CFLAGS ../ld/ldmacho.c + +ldpe.$O: ../ld/ldpe.c + $CC $CFLAGS ../ld/ldpe.c + +lib.$O: ../ld/lib.c + $CC $CFLAGS ../ld/lib.c + +macho.$O: ../ld/macho.c + $CC $CFLAGS ../ld/macho.c + +pe.$O: ../ld/pe.c + $CC $CFLAGS ../ld/pe.c + +symtab.$O: ../ld/symtab.c + $CC $CFLAGS ../ld/symtab.c diff -r d8d00747375b sys/src/cmd/ld/pe.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/src/cmd/ld/pe.c Mon Nov 14 17:35:25 2011 +0100 @@ -0,0 +1,660 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// PE (Portable Executable) file writing +// http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx + +#include "l.h" +#include "../ld/lib.h" +#include "../ld/pe.h" +#include "../ld/dwarf.h" + +// DOS stub that prints out +// "This program cannot be run in DOS mode." +static char dosstub[] = +{ + 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, + 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68, + 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, + 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, + 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, + 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20, + 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a, + 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +// Note: currently only up to 8 chars plus \0. +static char *symlabels[] = { + "symtab", "esymtab", "pclntab", "epclntab" +}; + +static Sym *rsrcsym; + +static char symnames[256]; +static int nextsymoff; + +int32 PESECTHEADR; +int32 PEFILEHEADR; + +static int pe64; +static int nsect; +static int nextsectoff; +static int nextfileoff; +static int textsect; + +static IMAGE_FILE_HEADER fh; +static IMAGE_OPTIONAL_HEADER oh; +static PE64_IMAGE_OPTIONAL_HEADER oh64; +static IMAGE_SECTION_HEADER sh[16]; +static IMAGE_DATA_DIRECTORY* dd; + +#define set(n, v) (pe64 ? (oh64.n = v) : (oh.n = v)) +#define put(v) (pe64 ? vputl(v) : lputl(v)) + +typedef struct Imp Imp; +struct Imp { + Sym* s; + uvlong off; + Imp* next; +}; + +typedef struct Dll Dll; +struct Dll { + char* name; + uvlong nameoff; + uvlong thunkoff; + Imp* ms; + Dll* next; +}; + +static Dll* dr; + +static Sym *dexport[1024]; +static int nexport; + +static IMAGE_SECTION_HEADER* +addpesection(char *name, int sectsize, int filesize) +{ + IMAGE_SECTION_HEADER *h; + + if(nsect == 16) { + diag("too many sections"); + errorexit(); + } + h = &sh[nsect++]; + strncpy((char*)h->Name, name, sizeof(h->Name)); + h->VirtualSize = sectsize; + h->VirtualAddress = nextsectoff; + nextsectoff = rnd(nextsectoff+sectsize, PESECTALIGN); + h->PointerToRawData = nextfileoff; + if(filesize > 0) { + h->SizeOfRawData = rnd(filesize, PEFILEALIGN); + nextfileoff += h->SizeOfRawData; + } + return h; +} + +static void +chksectoff(IMAGE_SECTION_HEADER *h, vlong off) +{ + if(off != h->PointerToRawData) { + diag("%s.PointerToRawData = %#llux, want %#llux", (char *)h->Name, (vlong)h->PointerToRawData, off); + errorexit(); + } +} + +static void +chksectseg(IMAGE_SECTION_HEADER *h, Segment *s) +{ + if(s->vaddr-PEBASE != h->VirtualAddress) { + diag("%s.VirtualAddress = %#llux, want %#llux", (char *)h->Name, (vlong)h->VirtualAddress, (vlong)(s->vaddr-PEBASE)); + errorexit(); + } + if(s->fileoff != h->PointerToRawData) { + diag("%s.PointerToRawData = %#llux, want %#llux", (char *)h->Name, (vlong)h->PointerToRawData, (vlong)(s->fileoff)); + errorexit(); + } +} + +void +peinit(void) +{ + int32 l; + + switch(thechar) { + // 64-bit architectures + case '6': + pe64 = 1; + l = sizeof(oh64); + dd = oh64.DataDirectory; + break; + // 32-bit architectures + default: + l = sizeof(oh); + dd = oh.DataDirectory; + break; + } + + PEFILEHEADR = rnd(sizeof(dosstub)+sizeof(fh)+l+sizeof(sh), PEFILEALIGN); + PESECTHEADR = rnd(PEFILEHEADR, PESECTALIGN); + nextsectoff = PESECTHEADR; + nextfileoff = PEFILEHEADR; +} + +static void +pewrite(void) +{ + cseek(0); + cwrite(dosstub, sizeof dosstub); + strnput("PE", 4); + // TODO: This code should not assume that the + // memory representation is little-endian or + // that the structs are packed identically to + // their file representation. + cwrite(&fh, sizeof fh); + if(pe64) + cwrite(&oh64, sizeof oh64); + else + cwrite(&oh, sizeof oh); + cwrite(sh, nsect * sizeof sh[0]); +} + +static void +strput(char *s) +{ + int n; + + for(n=0; *s; n++) + cput(*s++); + cput('\0'); + n++; + // string must be padded to even size + if(n%2) + cput('\0'); +} + +static Dll* +initdynimport(void) +{ + Imp *m; + Dll *d; + Sym *s, *dynamic; + + dr = nil; + m = nil; + for(s = allsym; s != S; s = s->allsym) { + if(!s->reachable || !s->dynimpname || s->dynexport) + continue; + for(d = dr; d != nil; d = d->next) { + if(strcmp(d->name,s->dynimplib) == 0) { + m = mal(sizeof *m); + break; + } + } + if(d == nil) { + d = mal(sizeof *d); + d->name = s->dynimplib; + d->next = dr; + dr = d; + m = mal(sizeof *m); + } + m->s = s; + m->next = d->ms; + d->ms = m; + } + + dynamic = lookup(".windynamic", 0); + dynamic->reachable = 1; + dynamic->type = SWINDOWS; + for(d = dr; d != nil; d = d->next) { + for(m = d->ms; m != nil; m = m->next) { + m->s->type = SWINDOWS | SSUB; + m->s->sub = dynamic->sub; + dynamic->sub = m->s; + m->s->value = dynamic->size; + dynamic->size += PtrSize; + } + dynamic->size += PtrSize; + } + + return dr; +} + +static void +addimports(IMAGE_SECTION_HEADER *datsect) +{ + IMAGE_SECTION_HEADER *isect; + uvlong n, oftbase, ftbase; + vlong startoff, endoff; + Imp *m; + Dll *d; + Sym* dynamic; + + startoff = cpos(); + dynamic = lookup(".windynamic", 0); + + // skip import descriptor table (will write it later) + n = 0; + for(d = dr; d != nil; d = d->next) + n++; + cseek(startoff + sizeof(IMAGE_IMPORT_DESCRIPTOR) * (n + 1)); + + // write dll names + for(d = dr; d != nil; d = d->next) { + d->nameoff = cpos() - startoff; + strput(d->name); + } + + // write function names + for(d = dr; d != nil; d = d->next) { + for(m = d->ms; m != nil; m = m->next) { + m->off = nextsectoff + cpos() - startoff; + wputl(0); // hint + strput(m->s->dynimpname); + } + } + + // write OriginalFirstThunks + oftbase = cpos() - startoff; + n = cpos(); + for(d = dr; d != nil; d = d->next) { + d->thunkoff = cpos() - n; + for(m = d->ms; m != nil; m = m->next) + put(m->off); + put(0); + } + + // add pe section and pad it at the end + n = cpos() - startoff; + isect = addpesection(".idata", n, n); + isect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA| + IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE; + chksectoff(isect, startoff); + strnput("", isect->SizeOfRawData - n); + endoff = cpos(); + + // write FirstThunks (allocated in .data section) + ftbase = dynamic->value - datsect->VirtualAddress - PEBASE; + cseek(datsect->PointerToRawData + ftbase); + for(d = dr; d != nil; d = d->next) { + for(m = d->ms; m != nil; m = m->next) + put(m->off); + put(0); + } + + // finally write import descriptor table + cseek(startoff); + for(d = dr; d != nil; d = d->next) { + lputl(isect->VirtualAddress + oftbase + d->thunkoff); + lputl(0); + lputl(0); + lputl(isect->VirtualAddress + d->nameoff); + lputl(datsect->VirtualAddress + ftbase + d->thunkoff); + } + lputl(0); //end + lputl(0); + lputl(0); + lputl(0); + lputl(0); + + // update data directory + dd[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect->VirtualAddress; + dd[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect->VirtualSize; + dd[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = dynamic->value - PEBASE; + dd[IMAGE_DIRECTORY_ENTRY_IAT].Size = dynamic->size; + + cseek(endoff); +} + +static int +scmp(const void *p1, const void *p2) +{ + Sym *s1, *s2; + + s1 = *(Sym**)p1; + s2 = *(Sym**)p2; + return strcmp(s1->dynimpname, s2->dynimpname); +} + +static void +initdynexport(void) +{ + Sym *s; + + nexport = 0; + for(s = allsym; s != S; s = s->allsym) { + if(!s->reachable || !s->dynimpname || !s->dynexport) + continue; + if(nexport+1 > sizeof(dexport)/sizeof(dexport[0])) { + diag("pe dynexport table is full"); + errorexit(); + } + + dexport[nexport] = s; + nexport++; + } + + qsort(dexport, nexport, sizeof dexport[0], scmp); +} + +void +addexports(void) +{ + IMAGE_SECTION_HEADER *sect; + IMAGE_EXPORT_DIRECTORY e; + int size, i, va, va_name, va_addr, va_na, v; + + size = sizeof e + 10*nexport + strlen(outfile) + 1; + for(i=0; idynimpname) + 1; + + if (nexport == 0) + return; + + sect = addpesection(".edata", size, size); + sect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ; + chksectoff(sect, cpos()); + va = sect->VirtualAddress; + dd[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = va; + dd[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect->VirtualSize; + + va_name = va + sizeof e + nexport*4; + va_addr = va + sizeof e; + va_na = va + sizeof e + nexport*8; + + e.Characteristics = 0; + e.MajorVersion = 0; + e.MinorVersion = 0; + e.NumberOfFunctions = nexport; + e.NumberOfNames = nexport; + e.Name = va + sizeof e + nexport*10; // Program names. + e.Base = 1; + e.AddressOfFunctions = va_addr; + e.AddressOfNames = va_name; + e.AddressOfNameOrdinals = va_na; + // put IMAGE_EXPORT_DIRECTORY + for (i=0; ivalue - PEBASE); + // put EXPORT Name Pointer Table + v = e.Name + strlen(outfile)+1; + for(i=0; idynimpname)+1; + } + // put EXPORT Ordinal Table + for(i=0; idynimpname, strlen(dexport[i]->dynimpname)+1); + strnput("", sect->SizeOfRawData - size); +} + +void +dope(void) +{ + Sym *rel; + + /* relocation table */ + rel = lookup(".rel", 0); + rel->reachable = 1; + rel->type = SELFROSECT; + + initdynimport(); + initdynexport(); +} + +/* + * For more than 8 characters section names, name contains a slash (/) that is + * followed by an ASCII representation of a decimal number that is an offset into + * the string table. + * reference: pecoff_v8.docx Page 24. + * + */ +IMAGE_SECTION_HEADER* +newPEDWARFSection(char *name, vlong size) +{ + IMAGE_SECTION_HEADER *h; + char s[8]; + + if(size == 0) + return nil; + + if(nextsymoff+strlen(name)+1 > sizeof(symnames)) { + diag("pe string table is full"); + errorexit(); + } + + strcpy(&symnames[nextsymoff], name); + sprint(s, "/%d\0", nextsymoff+4); + nextsymoff += strlen(name); + symnames[nextsymoff] = 0; + nextsymoff ++; + h = addpesection(s, size, size); + h->Characteristics = IMAGE_SCN_MEM_READ| + IMAGE_SCN_MEM_DISCARDABLE; + + return h; +} + +static void +addsymtable(void) +{ + IMAGE_SECTION_HEADER *h; + int i, size; + Sym *s; + + fh.NumberOfSymbols = sizeof(symlabels)/sizeof(symlabels[0]); + size = nextsymoff + 4 + 18*fh.NumberOfSymbols; + h = addpesection(".symtab", size, size); + h->Characteristics = IMAGE_SCN_MEM_READ| + IMAGE_SCN_MEM_DISCARDABLE; + chksectoff(h, cpos()); + fh.PointerToSymbolTable = cpos(); + + // put COFF symbol table + for (i=0; iname, 8); + lputl(datoff(s->value)); + wputl(textsect); + wputl(0x0308); // "array of structs" + cput(2); // storage class: external + cput(0); // no aux entries + } + + // put COFF string table + lputl(nextsymoff + 4); + for (i=0; iSizeOfRawData - size); +} + +void +setpersrc(Sym *sym) +{ + if(rsrcsym != nil) + diag("too many .rsrc sections"); + + rsrcsym = sym; +} + +void +addpersrc(void) +{ + IMAGE_SECTION_HEADER *h; + uchar *p; + uint32 val; + Reloc *r; + + if(rsrcsym == nil) + return; + + h = addpesection(".rsrc", rsrcsym->size, rsrcsym->size); + h->Characteristics = IMAGE_SCN_MEM_READ| + IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA; + chksectoff(h, cpos()); + // relocation + for(r=rsrcsym->r; rr+rsrcsym->nr; r++) { + p = rsrcsym->p + r->off; + val = h->VirtualAddress + r->add; + // 32-bit little-endian + p[0] = val; + p[1] = val>>8; + p[2] = val>>16; + p[3] = val>>24; + } + cwrite(rsrcsym->p, rsrcsym->size); + strnput("", h->SizeOfRawData - rsrcsym->size); + + // update data directory + dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h->VirtualAddress; + dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h->VirtualSize; +} + +static void +addexcept(IMAGE_SECTION_HEADER *text) +{ + IMAGE_SECTION_HEADER *pdata, *xdata; + vlong startoff; + uvlong n; + Sym *sym; + + if(thechar != '6') + return; + + // write unwind info + sym = lookup("runtime.sigtramp", 0); + startoff = cpos(); + lputl(9); // version=1, flags=UNW_FLAG_EHANDLER, rest 0 + lputl(sym->value - PEBASE); + lputl(0); + + n = cpos() - startoff; + xdata = addpesection(".xdata", n, n); + xdata->Characteristics = IMAGE_SCN_MEM_READ| + IMAGE_SCN_CNT_INITIALIZED_DATA; + chksectoff(xdata, startoff); + strnput("", xdata->SizeOfRawData - n); + + // write a function table entry for the whole text segment + startoff = cpos(); + lputl(text->VirtualAddress); + lputl(text->VirtualAddress + text->VirtualSize); + lputl(xdata->VirtualAddress); + + n = cpos() - startoff; + pdata = addpesection(".pdata", n, n); + pdata->Characteristics = IMAGE_SCN_MEM_READ| + IMAGE_SCN_CNT_INITIALIZED_DATA; + chksectoff(pdata, startoff); + strnput("", pdata->SizeOfRawData - n); + + dd[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress = pdata->VirtualAddress; + dd[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size = pdata->VirtualSize; +} + +void +asmbpe(void) +{ + IMAGE_SECTION_HEADER *t, *d; + + switch(thechar) { + default: + diag("unknown PE architecture"); + errorexit(); + case '6': + fh.Machine = IMAGE_FILE_MACHINE_AMD64; + break; + case '8': + fh.Machine = IMAGE_FILE_MACHINE_I386; + break; + } + + t = addpesection(".text", segtext.len, segtext.len); + t->Characteristics = IMAGE_SCN_CNT_CODE| + IMAGE_SCN_CNT_INITIALIZED_DATA| + IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ; + chksectseg(t, &segtext); + textsect = nsect; + + d = addpesection(".data", segdata.len, segdata.filelen); + d->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA| + IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE; + chksectseg(d, &segdata); + + if(!debug['s']) + dwarfaddpeheaders(); + + cseek(nextfileoff); + addimports(d); + addexports(); + addsymtable(); + addpersrc(); + addexcept(t); + + fh.NumberOfSections = nsect; + fh.TimeDateStamp = time(0); + fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED| + IMAGE_FILE_EXECUTABLE_IMAGE|IMAGE_FILE_DEBUG_STRIPPED; + if (pe64) { + fh.SizeOfOptionalHeader = sizeof(oh64); + fh.Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE; + set(Magic, 0x20b); // PE32+ + } else { + fh.SizeOfOptionalHeader = sizeof(oh); + fh.Characteristics |= IMAGE_FILE_32BIT_MACHINE; + set(Magic, 0x10b); // PE32 + oh.BaseOfData = d->VirtualAddress; + } + set(MajorLinkerVersion, 3); + set(MinorLinkerVersion, 0); + set(SizeOfCode, t->SizeOfRawData); + set(SizeOfInitializedData, d->SizeOfRawData); + set(SizeOfUninitializedData, 0); + set(AddressOfEntryPoint, entryvalue()-PEBASE); + set(BaseOfCode, t->VirtualAddress); + set(ImageBase, PEBASE); + set(SectionAlignment, PESECTALIGN); + set(FileAlignment, PEFILEALIGN); + set(MajorOperatingSystemVersion, 4); + set(MinorOperatingSystemVersion, 0); + set(MajorImageVersion, 1); + set(MinorImageVersion, 0); + set(MajorSubsystemVersion, 4); + set(MinorSubsystemVersion, 0); + set(SizeOfImage, nextsectoff); + set(SizeOfHeaders, PEFILEHEADR); + if(strcmp(headstring, "windowsgui") == 0) + set(Subsystem, IMAGE_SUBSYSTEM_WINDOWS_GUI); + else + set(Subsystem, IMAGE_SUBSYSTEM_WINDOWS_CUI); + + // Disable stack growth as we don't want Windows to + // fiddle with the thread stack limits, which we set + // ourselves to circumvent the stack checks in the + // Windows exception dispatcher. + // Commit size must be strictly less than reserve + // size otherwise reserve will be rounded up to a + // larger size, as verified with VMMap. + set(SizeOfStackReserve, 0x00010000); + set(SizeOfStackCommit, 0x0000ffff); + set(SizeOfHeapReserve, 0x00100000); + set(SizeOfHeapCommit, 0x00001000); + set(NumberOfRvaAndSizes, 16); + + pewrite(); +} diff -r d8d00747375b sys/src/cmd/ld/pe.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/src/cmd/ld/pe.h Mon Nov 14 17:35:25 2011 +0100 @@ -0,0 +1,179 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +typedef struct { + uint16 Machine; + uint16 NumberOfSections; + uint32 TimeDateStamp; + uint32 PointerToSymbolTable; + uint32 NumberOfSymbols; + uint16 SizeOfOptionalHeader; + uint16 Characteristics; +} IMAGE_FILE_HEADER; + +typedef struct { + uint32 VirtualAddress; + uint32 Size; +} IMAGE_DATA_DIRECTORY; + +typedef struct { + uint16 Magic; + uint8 MajorLinkerVersion; + uint8 MinorLinkerVersion; + uint32 SizeOfCode; + uint32 SizeOfInitializedData; + uint32 SizeOfUninitializedData; + uint32 AddressOfEntryPoint; + uint32 BaseOfCode; + uint32 BaseOfData; + uint32 ImageBase; + uint32 SectionAlignment; + uint32 FileAlignment; + uint16 MajorOperatingSystemVersion; + uint16 MinorOperatingSystemVersion; + uint16 MajorImageVersion; + uint16 MinorImageVersion; + uint16 MajorSubsystemVersion; + uint16 MinorSubsystemVersion; + uint32 Win32VersionValue; + uint32 SizeOfImage; + uint32 SizeOfHeaders; + uint32 CheckSum; + uint16 Subsystem; + uint16 DllCharacteristics; + uint32 SizeOfStackReserve; + uint32 SizeOfStackCommit; + uint32 SizeOfHeapReserve; + uint32 SizeOfHeapCommit; + uint32 LoaderFlags; + uint32 NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[16]; +} IMAGE_OPTIONAL_HEADER; + +typedef struct { + uint8 Name[8]; + uint32 VirtualSize; + uint32 VirtualAddress; + uint32 SizeOfRawData; + uint32 PointerToRawData; + uint32 PointerToRelocations; + uint32 PointerToLineNumbers; + uint16 NumberOfRelocations; + uint16 NumberOfLineNumbers; + uint32 Characteristics; +} IMAGE_SECTION_HEADER; + +typedef struct { + uint32 OriginalFirstThunk; + uint32 TimeDateStamp; + uint32 ForwarderChain; + uint32 Name; + uint32 FirstThunk; +} IMAGE_IMPORT_DESCRIPTOR; + +typedef struct _IMAGE_EXPORT_DIRECTORY { + uint32 Characteristics; + uint32 TimeDateStamp; + uint16 MajorVersion; + uint16 MinorVersion; + uint32 Name; + uint32 Base; + uint32 NumberOfFunctions; + uint32 NumberOfNames; + uint32 AddressOfFunctions; + uint32 AddressOfNames; + uint32 AddressOfNameOrdinals; +} IMAGE_EXPORT_DIRECTORY; + +#define PEBASE 0x00400000 +// SectionAlignment must be greater than or equal to FileAlignment. +// The default is the page size for the architecture. +#define PESECTALIGN 0x1000 +// FileAlignment should be a power of 2 between 512 and 64 K, inclusive. +// The default is 512. If the SectionAlignment is less than +// the architecture's page size, then FileAlignment must match SectionAlignment. +#define PEFILEALIGN (2<<8) +extern int32 PESECTHEADR; +extern int32 PEFILEHEADR; + +enum { + IMAGE_FILE_MACHINE_I386 = 0x14c, + IMAGE_FILE_MACHINE_AMD64 = 0x8664, + + IMAGE_FILE_RELOCS_STRIPPED = 0x0001, + IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002, + IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020, + IMAGE_FILE_32BIT_MACHINE = 0x0100, + IMAGE_FILE_DEBUG_STRIPPED = 0x0200, + + IMAGE_SCN_CNT_CODE = 0x00000020, + IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040, + IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080, + IMAGE_SCN_MEM_EXECUTE = 0x20000000, + IMAGE_SCN_MEM_READ = 0x40000000, + IMAGE_SCN_MEM_WRITE = 0x80000000, + IMAGE_SCN_MEM_DISCARDABLE = 0x2000000, + + IMAGE_DIRECTORY_ENTRY_EXPORT = 0, + IMAGE_DIRECTORY_ENTRY_IMPORT = 1, + IMAGE_DIRECTORY_ENTRY_RESOURCE = 2, + IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3, + IMAGE_DIRECTORY_ENTRY_SECURITY = 4, + IMAGE_DIRECTORY_ENTRY_BASERELOC = 5, + IMAGE_DIRECTORY_ENTRY_DEBUG = 6, + IMAGE_DIRECTORY_ENTRY_COPYRIGHT = 7, + IMAGE_DIRECTORY_ENTRY_ARCHITECTURE = 7, + IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8, + IMAGE_DIRECTORY_ENTRY_TLS = 9, + IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10, + IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11, + IMAGE_DIRECTORY_ENTRY_IAT = 12, + IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13, + IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14, + + IMAGE_SUBSYSTEM_WINDOWS_GUI = 2, + IMAGE_SUBSYSTEM_WINDOWS_CUI = 3, +}; + +void peinit(void); +void asmbpe(void); +void dope(void); + +IMAGE_SECTION_HEADER* newPEDWARFSection(char *name, vlong size); + +// X64 +typedef struct { + uint16 Magic; + uint8 MajorLinkerVersion; + uint8 MinorLinkerVersion; + uint32 SizeOfCode; + uint32 SizeOfInitializedData; + uint32 SizeOfUninitializedData; + uint32 AddressOfEntryPoint; + uint32 BaseOfCode; + uint64 ImageBase; + uint32 SectionAlignment; + uint32 FileAlignment; + uint16 MajorOperatingSystemVersion; + uint16 MinorOperatingSystemVersion; + uint16 MajorImageVersion; + uint16 MinorImageVersion; + uint16 MajorSubsystemVersion; + uint16 MinorSubsystemVersion; + uint32 Win32VersionValue; + uint32 SizeOfImage; + uint32 SizeOfHeaders; + uint32 CheckSum; + uint16 Subsystem; + uint16 DllCharacteristics; + uint64 SizeOfStackReserve; + uint64 SizeOfStackCommit; + uint64 SizeOfHeapReserve; + uint64 SizeOfHeapCommit; + uint32 LoaderFlags; + uint32 NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[16]; +} PE64_IMAGE_OPTIONAL_HEADER; + +void setpersrc(Sym *sym); diff -r d8d00747375b sys/src/cmd/ld/stack.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/src/cmd/ld/stack.h Mon Nov 14 17:35:25 2011 +0100 @@ -0,0 +1,97 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Stack layout parameters. +Included both by runtime (compiled via 6c) and linkers (compiled via gcc). + +The per-goroutine g->stackguard is set to point StackGuard bytes +above the bottom of the stack. Each function compares its stack +pointer against g->stackguard to check for overflow. To cut one +instruction from the check sequence for functions with tiny frames, +the stack is allowed to protrude StackSmall bytes below the stack +guard. Functions with large frames don't bother with the check and +always call morestack. The sequences are (for amd64, others are +similar): + + guard = g->stackguard + frame = function's stack frame size + argsize = size of function arguments (call + return) + + stack frame size <= StackSmall: + CMPQ guard, SP + JHI 3(PC) + MOVQ m->morearg, $(argsize << 32) + CALL morestack(SB) + + stack frame size > StackSmall but < StackBig + LEAQ (frame-StackSmall)(SP), R0 + CMPQ guard, R0 + JHI 3(PC) + MOVQ m->morearg, $(argsize << 32) + CALL morestack(SB) + + stack frame size >= StackBig: + MOVQ m->morearg, $((argsize << 32) | frame) + CALL morestack(SB) + +The bottom StackGuard - StackSmall bytes are important: there has +to be enough room to execute functions that refuse to check for +stack overflow, either because they need to be adjacent to the +actual caller's frame (deferproc) or because they handle the imminent +stack overflow (morestack). + +For example, deferproc might call malloc, which does one of the +above checks (without allocating a full frame), which might trigger +a call to morestack. This sequence needs to fit in the bottom +section of the stack. On amd64, morestack's frame is 40 bytes, and +deferproc's frame is 56 bytes. That fits well within the +StackGuard - StackSmall = 128 bytes at the bottom. +The linkers explore all possible call traces involving non-splitting +functions to make sure that this limit cannot be violated. + */ + +enum { + // StackSystem is a number of additional bytes to add + // to each stack below the usual guard area for OS-specific + // purposes like signal handling. Used on Windows because + // it does not use a separate stack. +#ifdef __WINDOWS__ + StackSystem = 512 * sizeof(uintptr), +#else + StackSystem = 0, +#endif + + // The amount of extra stack to allocate beyond the size + // needed for the single frame that triggered the split. + StackExtra = 1024, + + // The minimum stack segment size to allocate. + // If the amount needed for the splitting frame + StackExtra + // is less than this number, the stack will have this size instead. + StackMin = 4096, + FixedStack = StackMin + StackSystem, + + // Functions that need frames bigger than this call morestack + // unconditionally. That is, on entry to a function it is assumed + // that the amount of space available in the current stack segment + // couldn't possibly be bigger than StackBig. If stack segments + // do run with more space than StackBig, the space may not be + // used efficiently. As a result, StackBig should not be significantly + // smaller than StackMin or StackExtra. + StackBig = 4096, + + // The stack guard is a pointer this many bytes above the + // bottom of the stack. + StackGuard = 256 + StackSystem, + + // After a stack split check the SP is allowed to be this + // many bytes below the stack guard. This saves an instruction + // in the checking sequence for tiny frames. + StackSmall = 128, + + // The maximum number of bytes that a chain of NOSPLIT + // functions can use. + StackLimit = StackGuard - StackSystem - StackSmall, +}; diff -r d8d00747375b sys/src/cmd/ld/symtab.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/src/cmd/ld/symtab.c Mon Nov 14 17:35:25 2011 +0100 @@ -0,0 +1,375 @@ +// Inferno utils/6l/span.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.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. + +// Symbol table. + +#include "l.h" +#include "../ld/lib.h" +#include "../ld/elf.h" + +static int maxelfstr; + +int +putelfstr(char *s) +{ + int off, n; + + if(elfstrsize == 0 && s[0] != 0) { + // first entry must be empty string + putelfstr(""); + } + + n = strlen(s)+1; + if(elfstrsize+n > maxelfstr) { + maxelfstr = 2*(elfstrsize+n+(1<<20)); + elfstrdat = realloc(elfstrdat, maxelfstr); + } + off = elfstrsize; + elfstrsize += n; + memmove(elfstrdat+off, s, n); + return off; +} + +void +putelfsyment(int off, vlong addr, vlong size, int info, int shndx) +{ + switch(thechar) { + case '6': + LPUT(off); + cput(info); + cput(0); + WPUT(shndx); + VPUT(addr); + VPUT(size); + symsize += ELF64SYMSIZE; + break; + default: + LPUT(off); + LPUT(addr); + LPUT(size); + cput(info); + cput(0); + WPUT(shndx); + symsize += ELF32SYMSIZE; + break; + } +} + +void +putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) +{ + int bind, type, shndx, off; + + USED(go); + switch(t) { + default: + return; + case 'T': + type = STT_FUNC; + shndx = elftextsh + 0; + break; + case 'D': + type = STT_OBJECT; + if((x->type&~SSUB) == SRODATA) + shndx = elftextsh + 1; + else + shndx = elftextsh + 2; + break; + case 'B': + type = STT_OBJECT; + shndx = elftextsh + 3; + break; + } + bind = ver ? STB_LOCAL : STB_GLOBAL; + off = putelfstr(s); + putelfsyment(off, addr, size, (bind<<4)|(type&0xf), shndx); +} + +void +asmelfsym(void) +{ + // the first symbol entry is reserved + putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_NOTYPE, 0); + genasmsym(putelfsym); +} + +void +putplan9sym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) +{ + int i; + + USED(go); + USED(ver); + USED(size); + USED(x); + switch(t) { + case 'T': + case 'L': + case 'D': + case 'B': + if(ver) + t += 'a' - 'A'; + case 'a': + case 'p': + case 'f': + case 'z': + case 'Z': + case 'm': + lputb(addr); + cput(t+0x80); /* 0x80 is variable length */ + + if(t == 'z' || t == 'Z') { + cput(s[0]); + for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) { + cput(s[i]); + cput(s[i+1]); + } + cput(0); + cput(0); + i++; + } else { + /* skip the '<' in filenames */ + if(t == 'f') + s++; + for(i=0; s[i]; i++) + cput(s[i]); + cput(0); + } + symsize += 4 + 1 + i + 1; + break; + default: + return; + }; +} + +void +asmplan9sym(void) +{ + genasmsym(putplan9sym); +} + +static Sym *symt; + +static void +scput(int b) +{ + uchar *p; + + symgrow(symt, symt->size+1); + p = symt->p + symt->size; + *p = b; + symt->size++; +} + +static void +slputb(int32 v) +{ + uchar *p; + + symgrow(symt, symt->size+4); + p = symt->p + symt->size; + *p++ = v>>24; + *p++ = v>>16; + *p++ = v>>8; + *p = v; + symt->size += 4; +} + +void +wputl(ushort w) +{ + cput(w); + cput(w>>8); +} + +void +wputb(ushort w) +{ + cput(w>>8); + cput(w); +} + +void +lputb(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 +vputb(uint64 v) +{ + lputb(v>>32); + lputb(v); +} + +void +vputl(uint64 v) +{ + lputl(v); + lputl(v >> 32); +} + +void +putsymb(Sym *s, char *name, int t, vlong v, vlong size, int ver, Sym *typ) +{ + int i, f, l; + Reloc *rel; + + USED(size); + if(t == 'f') + name++; + l = 4; +// if(!debug['8']) +// l = 8; + if(s != nil) { + rel = addrel(symt); + rel->siz = l + Rbig; + rel->sym = s; + rel->type = D_ADDR; + rel->off = symt->size; + v = 0; + } + if(l == 8) + slputb(v>>32); + slputb(v); + if(ver) + t += 'a' - 'A'; + scput(t+0x80); /* 0x80 is variable length */ + + if(t == 'Z' || t == 'z') { + scput(name[0]); + for(i=1; name[i] != 0 || name[i+1] != 0; i += 2) { + scput(name[i]); + scput(name[i+1]); + } + scput(0); + scput(0); + } + else { + for(i=0; name[i]; i++) + scput(name[i]); + scput(0); + } + if(typ) { + if(!typ->reachable) + diag("unreachable type %s", typ->name); + rel = addrel(symt); + rel->siz = l; + rel->sym = typ; + rel->type = D_ADDR; + rel->off = symt->size; + } + if(l == 8) + slputb(0); + slputb(0); + + if(debug['n']) { + if(t == 'z' || t == 'Z') { + Bprint(&bso, "%c %.8llux ", t, v); + for(i=1; name[i] != 0 || name[i+1] != 0; i+=2) { + f = ((name[i]&0xff) << 8) | (name[i+1]&0xff); + Bprint(&bso, "/%x", f); + } + Bprint(&bso, "\n"); + return; + } + if(ver) + Bprint(&bso, "%c %.8llux %s<%d> %s\n", t, v, s->name, ver, typ ? typ->name : ""); + else + Bprint(&bso, "%c %.8llux %s %s\n", t, v, s->name, typ ? typ->name : ""); + } +} + +void +symtab(void) +{ + Sym *s; + + // Define these so that they'll get put into the symbol table. + // data.c:/^address will provide the actual values. + xdefine("text", STEXT, 0); + xdefine("etext", STEXT, 0); + xdefine("rodata", SRODATA, 0); + xdefine("erodata", SRODATA, 0); + xdefine("data", SBSS, 0); + xdefine("edata", SBSS, 0); + xdefine("end", SBSS, 0); + xdefine("epclntab", SRODATA, 0); + xdefine("esymtab", SRODATA, 0); + + // pseudo-symbols to mark locations of type, string, and go string data. + s = lookup("type.*", 0); + s->type = STYPE; + s->size = 0; + s->reachable = 1; + + s = lookup("go.string.*", 0); + s->type = SGOSTRING; + s->size = 0; + s->reachable = 1; + + symt = lookup("symtab", 0); + symt->type = SSYMTAB; + symt->size = 0; + symt->reachable = 1; + + // assign specific types so that they sort together. + // within a type they sort by size, so the .* symbols + // just defined above will be first. + // hide the specific symbols. + for(s = allsym; s != S; s = s->allsym) { + if(!s->reachable || s->special || s->type != SRODATA) + continue; + if(strncmp(s->name, "type.", 5) == 0) { + s->type = STYPE; + s->hide = 1; + } + if(strncmp(s->name, "go.string.", 10) == 0) { + s->type = SGOSTRING; + s->hide = 1; + } + } + + if(debug['s']) + return; + genasmsym(putsymb); +} diff -r d8d00747375b sys/src/libbio/bbuffered.c --- a/sys/src/libbio/bbuffered.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/libbio/bbuffered.c Mon Nov 14 17:35:25 2011 +0100 @@ -3,7 +3,7 @@ #include int -Bbuffered(Biobufhdr *bp) +Bbuffered(Biobuf *bp) { switch(bp->state) { case Bracteof: diff -r d8d00747375b sys/src/libbio/bfildes.c --- a/sys/src/libbio/bfildes.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/libbio/bfildes.c Mon Nov 14 17:35:25 2011 +0100 @@ -3,7 +3,7 @@ #include int -Bfildes(Biobufhdr *bp) +Bfildes(Biobuf *bp) { return bp->fid; diff -r d8d00747375b sys/src/libbio/bflush.c --- a/sys/src/libbio/bflush.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/libbio/bflush.c Mon Nov 14 17:35:25 2011 +0100 @@ -3,7 +3,7 @@ #include int -Bflush(Biobufhdr *bp) +Bflush(Biobuf *bp) { int n, c; diff -r d8d00747375b sys/src/libbio/bgetc.c --- a/sys/src/libbio/bgetc.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/libbio/bgetc.c Mon Nov 14 17:35:25 2011 +0100 @@ -3,7 +3,7 @@ #include int -Bgetc(Biobufhdr *bp) +Bgetc(Biobuf *bp) { int i; @@ -42,7 +42,7 @@ } int -Bungetc(Biobufhdr *bp) +Bungetc(Biobuf *bp) { if(bp->state == Bracteof) diff -r d8d00747375b sys/src/libbio/bgetd.c --- a/sys/src/libbio/bgetd.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/libbio/bgetd.c Mon Nov 14 17:35:25 2011 +0100 @@ -1,10 +1,10 @@ -#include -#include -#include +#include +#include +#include struct bgetd { - Biobufhdr* b; + Biobuf* b; int eof; }; @@ -21,14 +21,18 @@ } int -Bgetd(Biobufhdr *bp, double *dp) +Bgetd(Biobuf *bp, double *dp) { double d; struct bgetd b; b.b = bp; b.eof = 0; +#ifdef PLAN9PORT + d = fmtcharstod(Bgetdf, &b); +#else d = charstod(Bgetdf, &b); +#endif if(b.eof) return -1; Bungetc(bp); diff -r d8d00747375b sys/src/libbio/bgetrune.c --- a/sys/src/libbio/bgetrune.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/libbio/bgetrune.c Mon Nov 14 17:35:25 2011 +0100 @@ -3,11 +3,11 @@ #include long -Bgetrune(Biobufhdr *bp) +Bgetrune(Biobuf *bp) { int c, i; Rune rune; - char str[4]; + char str[UTFmax]; c = Bgetc(bp); if(c < Runeself) { /* one char */ @@ -34,7 +34,7 @@ } int -Bungetrune(Biobufhdr *bp) +Bungetrune(Biobuf *bp) { if(bp->state == Bracteof) diff -r d8d00747375b sys/src/libbio/binit.c --- a/sys/src/libbio/binit.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/libbio/binit.c Mon Nov 14 17:35:25 2011 +0100 @@ -2,17 +2,22 @@ #include #include -static Biobufhdr* wbufs[20]; +enum +{ + MAXBUFS = 20 +}; + +static Biobuf* wbufs[MAXBUFS]; static int atexitflag; static void batexit(void) { - Biobufhdr *bp; + Biobuf *bp; int i; - for(i=0; ib, sizeof(bp->b)); + bp->flag = Bmagic; + return bp; +} + +Biobuf* Bopen(char *name, int mode) { Biobuf *bp; int f; - switch(mode&~(OCEXEC|ORCLOSE|OTRUNC)) { + switch(mode&~(ORCLOSE|OTRUNC)) { default: - fprint(2, "Bopen: unknown mode %#x\n", mode); + fprint(2, "Bopen: unknown mode %d\n", mode); return 0; + case OREAD: - f = open(name, mode); + f = open(name, OREAD); + if(f < 0) + return 0; break; + case OWRITE: - f = create(name, mode, 0666); - break; + f = create(name, OWRITE|OTRUNC, 0666); + if(f < 0) + return 0; } - if(f < 0) - return 0; - bp = malloc(sizeof(Biobuf)); - Binits(bp, f, mode, bp->b, sizeof(bp->b)); - bp->flag = Bmagic; /* mark bp open & malloced */ + bp = Bfdopen(f, mode); + if(bp == 0) + close(f); return bp; } int -Bterm(Biobufhdr *bp) +Bterm(Biobuf *bp) { - int r; deinstall(bp); - r = Bflush(bp); + Bflush(bp); if(bp->flag == Bmagic) { bp->flag = 0; close(bp->fid); - bp->fid = -1; /* prevent accidents */ free(bp); } - /* otherwise opened with Binit(s) */ - return r; + return 0; } diff -r d8d00747375b sys/src/libbio/boffset.c --- a/sys/src/libbio/boffset.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/libbio/boffset.c Mon Nov 14 17:35:25 2011 +0100 @@ -3,7 +3,7 @@ #include vlong -Boffset(Biobufhdr *bp) +Boffset(Biobuf *bp) { vlong n; diff -r d8d00747375b sys/src/libbio/bprint.c --- a/sys/src/libbio/bprint.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/libbio/bprint.c Mon Nov 14 17:35:25 2011 +0100 @@ -3,13 +3,56 @@ #include int -Bprint(Biobufhdr *bp, char *fmt, ...) +Bprint(Biobuf *bp, char *fmt, ...) { + int n; va_list arg; - int n; va_start(arg, fmt); n = Bvprint(bp, fmt, arg); va_end(arg); return n; } + +static int +bflush(Fmt *f) +{ + Biobuf *bp; + + if(f->stop == nil) + return 0; + + bp = f->farg; + bp->ocount = (char*)f->to - (char*)f->stop; + if(Bflush(bp) < 0) { + f->stop = nil; + f->to = nil; + return 0; + } + f->to = (char*)f->stop + bp->ocount; + + return 1; +} + +int +Bvprint(Biobuf *bp, char *fmt, va_list arg) +{ + int n; + Fmt f; + + memset(&f, 0, sizeof f); +#ifdef PLAN9PORT + fmtlocaleinit(&f, nil, nil, nil); +#endif + f.stop = bp->ebuf; + f.to = (char*)f.stop + bp->ocount; + f.flush = bflush; + f.farg = bp; + + n = fmtvprint(&f, fmt, arg); + + if(f.stop != nil) + bp->ocount = (char*)f.to - (char*)f.stop; + + return n; +} diff -r d8d00747375b sys/src/libbio/bputc.c --- a/sys/src/libbio/bputc.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/libbio/bputc.c Mon Nov 14 17:35:25 2011 +0100 @@ -3,7 +3,7 @@ #include int -Bputc(Biobufhdr *bp, int c) +Bputc(Biobuf *bp, int c) { int i; diff -r d8d00747375b sys/src/libbio/bputrune.c --- a/sys/src/libbio/bputrune.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/libbio/bputrune.c Mon Nov 14 17:35:25 2011 +0100 @@ -3,10 +3,10 @@ #include int -Bputrune(Biobufhdr *bp, long c) +Bputrune(Biobuf *bp, long c) { Rune rune; - char str[4]; + char str[UTFmax]; int n; rune = c; diff -r d8d00747375b sys/src/libbio/brdline.c --- a/sys/src/libbio/brdline.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/libbio/brdline.c Mon Nov 14 17:35:25 2011 +0100 @@ -3,7 +3,7 @@ #include void* -Brdline(Biobufhdr *bp, int delim) +Brdline(Biobuf *bp, int delim) { char *ip, *ep; int i, j; @@ -88,7 +88,7 @@ } int -Blinelen(Biobufhdr *bp) +Blinelen(Biobuf *bp) { return bp->rdline; diff -r d8d00747375b sys/src/libbio/brdstr.c --- a/sys/src/libbio/brdstr.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/libbio/brdstr.c Mon Nov 14 17:35:25 2011 +0100 @@ -2,111 +2,37 @@ #include #include -static char* -badd(char *p, int *np, char *data, int ndata, int delim, int nulldelim) +char* +Brdstr(Biobuf *bp, int delim, int nulldelim) { - int n; + char *p, *q, *nq; + int n, linelen; - n = *np; - p = realloc(p, n+ndata+1); - if(p){ - memmove(p+n, data, ndata); - n += ndata; - if(n>0 && nulldelim && p[n-1]==delim) - p[--n] = '\0'; - else - p[n] = '\0'; - *np = n; - } - return p; -} - -char* -Brdstr(Biobufhdr *bp, int delim, int nulldelim) -{ - char *ip, *ep, *p; - int i, j; - - i = -bp->icount; - bp->rdline = 0; - if(i == 0) { - /* - * eof or other error - */ - if(bp->state != Bractive) { - if(bp->state == Bracteof) - bp->state = Bractive; - bp->gbuf = bp->ebuf; + q = nil; + n = 0; + for(;;) { + p = Brdline(bp, delim); + linelen = Blinelen(bp); + if(n == 0 && linelen == 0) + return nil; + nq = realloc(q, n+linelen+1); + if(nq == nil) { + free(q); return nil; } + q = nq; + if(p != nil) { + memmove(q+n, p, linelen); + n += linelen; + if(nulldelim) + q[n-1] = '\0'; + break; + } + if(linelen == 0) + break; + Bread(bp, q+n, linelen); + n += linelen; } - - /* - * first try in remainder of buffer (gbuf doesn't change) - */ - ip = (char*)bp->ebuf - i; - ep = memchr(ip, delim, i); - if(ep) { - j = (ep - ip) + 1; - bp->icount += j; - return badd(nil, &bp->rdline, ip, j, delim, nulldelim); - } - - /* - * copy data to beginning of buffer - */ - if(i < bp->bsize) - memmove(bp->bbuf, ip, i); - bp->gbuf = bp->bbuf; - - /* - * append to buffer looking for the delim - */ - p = nil; - for(;;){ - ip = (char*)bp->bbuf + i; - while(i < bp->bsize) { - j = read(bp->fid, ip, bp->bsize-i); - if(j <= 0 && i == 0) - return p; - if(j <= 0 && i > 0){ - /* - * end of file but no delim. pretend we got a delim - * by making the delim \0 and smashing it with nulldelim. - */ - j = 1; - ep = ip; - delim = '\0'; - nulldelim = 1; - *ep = delim; /* there will be room for this */ - }else{ - bp->offset += j; - ep = memchr(ip, delim, j); - } - i += j; - if(ep) { - /* - * found in new piece - * copy back up and reset everything - */ - ip = (char*)bp->ebuf - i; - if(i < bp->bsize){ - memmove(ip, bp->bbuf, i); - bp->gbuf = (uchar*)ip; - } - j = (ep - (char*)bp->bbuf) + 1; - bp->icount = j - i; - return badd(p, &bp->rdline, ip, j, delim, nulldelim); - } - ip += j; - } - - /* - * full buffer without finding; add to user string and continue - */ - p = badd(p, &bp->rdline, (char*)bp->bbuf, bp->bsize, 0, 0); - i = 0; - bp->icount = 0; - bp->gbuf = bp->ebuf; - } + q[n] = '\0'; + return q; } diff -r d8d00747375b sys/src/libbio/bread.c --- a/sys/src/libbio/bread.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/libbio/bread.c Mon Nov 14 17:35:25 2011 +0100 @@ -3,7 +3,7 @@ #include long -Bread(Biobufhdr *bp, void *ap, long count) +Bread(Biobuf *bp, void *ap, long count) { long c; uchar *p; @@ -42,7 +42,5 @@ p += n; } bp->icount = ic; - if(count == c && bp->state == Binactive) - return -1; return count-c; } diff -r d8d00747375b sys/src/libbio/bseek.c --- a/sys/src/libbio/bseek.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/libbio/bseek.c Mon Nov 14 17:35:25 2011 +0100 @@ -3,9 +3,10 @@ #include vlong -Bseek(Biobufhdr *bp, vlong offset, int base) +Bseek(Biobuf *bp, vlong offset, int base) { vlong n, d; + int bufsz; switch(bp->state) { default: @@ -28,16 +29,18 @@ * try to seek within buffer */ if(base == 0) { - /* - * if d is too large for an int, icount may wrap, - * so we need to ensure that icount hasn't wrapped - * and points within the buffer's valid data. - */ d = n - Boffset(bp); - bp->icount += d; - if(d <= bp->bsize && bp->icount <= 0 && - bp->ebuf - bp->gbuf >= -bp->icount) - return n; + bufsz = bp->ebuf - bp->gbuf; + if(-bufsz <= d && d <= bufsz){ + bp->icount += d; + if(d >= 0) { + if(bp->icount <= 0) + return n; + } else { + if(bp->ebuf - bp->gbuf >= -bp->icount) + return n; + } + } } /* diff -r d8d00747375b sys/src/libbio/btestprint.c --- a/sys/src/libbio/btestprint.c Thu Sep 29 03:00:00 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -#include -#include -#include - -void -main(int argc, char **argv) -{ - Biobuf b; - char *s; - int n; - - - n = atoi(argv[1]); - s = malloc(n+1); - memset(s, 'a', n); - s[n] = '\0'; - Binit(&b, 1, OWRITE); - Bprint(&b, "%s\n", s); - Bflush(&b); -} diff -r d8d00747375b sys/src/libbio/bvprint.c --- a/sys/src/libbio/bvprint.c Thu Sep 29 03:00:00 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -#include -#include -#include - -static int -fmtBflush(Fmt *f) -{ - Biobufhdr *bp; - - bp = f->farg; - bp->ocount = (char*)f->to - (char*)f->stop; - if(Bflush(bp) < 0) - return 0; - f->stop = bp->ebuf; - f->to = (char*)f->stop + bp->ocount; - f->start = f->to; - return 1; -} - -int -Bvprint(Biobufhdr *bp, char *fmt, va_list arg) -{ - int n; - Fmt f; - - f.runes = 0; - f.stop = bp->ebuf; - f.start = (char*)f.stop + bp->ocount; - f.to = f.start; - f.flush = fmtBflush; - f.farg = bp; - f.nfmt = 0; - f.args = arg; - n = dofmt(&f, fmt); - bp->ocount = (char*)f.to - (char*)f.stop; - return n; -} diff -r d8d00747375b sys/src/libbio/bwrite.c --- a/sys/src/libbio/bwrite.c Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/libbio/bwrite.c Mon Nov 14 17:35:25 2011 +0100 @@ -3,12 +3,11 @@ #include long -Bwrite(Biobufhdr *bp, void *ap, long count) +Bwrite(Biobuf *bp, void *ap, long count) { long c; uchar *p; int i, n, oc; - char errbuf[ERRMAX]; p = ap; c = count; @@ -23,10 +22,7 @@ return Beof; i = write(bp->fid, bp->bbuf, bp->bsize); if(i != bp->bsize) { - errstr(errbuf, sizeof errbuf); - if(strstr(errbuf, "interrupt") == nil) - bp->state = Binactive; - errstr(errbuf, sizeof errbuf); + bp->state = Binactive; return Beof; } bp->offset += i; diff -r d8d00747375b sys/src/libbio/mkfile --- a/sys/src/libbio/mkfile Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/libbio/mkfile Mon Nov 14 17:35:25 2011 +0100 @@ -5,20 +5,19 @@ bbuffered.$O\ bfildes.$O\ bflush.$O\ - bgetrune.$O\ bgetc.$O\ bgetd.$O\ + bgetrune.$O\ binit.$O\ boffset.$O\ bprint.$O\ + bputc.$O\ bputrune.$O\ - bputc.$O\ brdline.$O\ brdstr.$O\ bread.$O\ bseek.$O\ bwrite.$O\ - bvprint.$O\ HFILES=/sys/include/bio.h diff -r d8d00747375b sys/src/libc/port/goos.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/src/libc/port/goos.c Mon Nov 14 17:35:25 2011 +0100 @@ -0,0 +1,46 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include +#include + +char GOOS[32]; +char GOARCH[32]; +char GOROOT[32]; +char GOVERSION[32]; + +static char* +defgetenv(char *name, char *def) +{ + char *p; + + p = getenv(name); + if(p == nil || p[0] == '\0') + p = def; + return p; +} + +char* +getgoos(void) +{ + return defgetenv("GOOS", GOOS); +} + +char* +getgoarch(void) +{ + return defgetenv("GOARCH", GOARCH); +} + +char* +getgoroot(void) +{ + return defgetenv("GOROOT", GOROOT); +} + +char* +getgoversion(void) +{ + return GOVERSION; +} diff -r d8d00747375b sys/src/libc/port/mkfile --- a/sys/src/libc/port/mkfile Thu Sep 29 03:00:00 2011 +0200 +++ b/sys/src/libc/port/mkfile Mon Nov 14 17:35:25 2011 +0100 @@ -30,6 +30,7 @@ getcallerpc.c\ getfields.c\ getuser.c\ + goos.c\ hangup.c\ hypot.c\ lnrand.c\